朱博的技术园

关注基于.Net的Web解决方案,高性能数据库设计,高性能Web服务解决方案,关注移动开发

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  22 随笔 :: 0 文章 :: 349 评论 :: 3 引用

2011年11月23日 #

前言

我写Android 刚不久,发现一个Android应用是否有更多人用,不仅取决于应用本身,还取决于应用的推广,在中国,起码就有以下十个市场需要推广:360开放平台、爱米吧、谷歌电子市场、安智市场、应用汇、优亿市场、机锋、安卓市场、N多、安卓星空。

为了衡量每个市场的效果,我使用了友盟的分发渠道分析接口,只需要为不同的市场在 AndroidManifest.xml 里定义不同的 meta-data UMENG_CHANNEL 值,然后为各市场分发各自的apk即可。

这时问题就来了,如果我的应用有更新,如果没有一个自动化的方法,我需要用eclipse手动export、签名…… ,光敲签名时的storepass和keypass就够受的了,更不用说还得每次记得修改签名文件代表不同市场的后缀,比如MyApp_360.apk、MyApp_androidmarket.apk……,非常容易出错,也很浪费时间。

于是我花了1天的时间,用powershell脚本将上面的操作自动化了,感觉很棒,和大家分享一下,希望能够帮到各位。

在阅读这篇文章之前,我假设您已经知道如何给Android 应用签名,了解apache ant,已经集成了友盟分发渠道分析接口,了解PowerShell。

实现思路

  1. 用PowerShell实现一个方法:使用ant自动编译项目,在每次编译之前,修改 AndroidManifest.xml 中meta-data UMENG_CHANNEL 的值为指定市场的标识。
  2. 用字符串数组存储所有市场的标识,遍历该数组,遍历至每个元素时,都将该元素传入上面的方法,可实现针对不同的市场进行编译,编译完成后,再对编译好的应用签名即可。

系统环境

  • Windows 7 Untimate
  • JDK 7 Update1,假设路径为: E:\Program Files\Java\jdk1.7.0_01
  • apache-ant-1.8.2,假设路径为:E:\Program Files\apache-ant-1.8.2
  • Android SDK,假设路径为:E:\Program Files\Android\android-sdk

用ant自动编译项目

  • 假设Android项目路径为:D:\workspace\MyApp
  • 检查是否存在文件D:\workspace\MyApp\build.xml,这是使用ant编译项目时需要用到的配置文件
    • 若不存在,在command窗口中执行:
      • CD D:\workspace\MyApp
      • D:
      • "E:\Program Files\Android\android-sdk\tools\android" update project --path .
    • 若存在或通过上面的步骤生成了build.xml,修改文件中<project name="xxx" default="help"> xxx为自己项目的名称(项目名称如何改,参见文末的更新),如:<project name="MyApp" default="help">
  • 新建批处理文件D:\workspace\MyApp\build.bat,该文件使用ant对android项目自动编译,文件内容如下,请根据自己项目、系统的实际情况修改路径
1 SET JAVA_HOME=E:\Program Files\Java\jdk1.7.0_01
2 cd D:\workspace\MyApp
3 D:
4 "E:\Program Files\apache-ant-1.8.2\bin\ant" release

如果系统环境没问题,build.bat执行后,在目录 D:\workspace\MyApp\bin 中应该可以看到编译好的MyApp-release-unsigned.apk。

注意:如果项目中有引用的第三方jar包类库,要把这些类库放到项目根目录的 "libs" 目录下,否则,ant在编译的时候会出错。

流程详解

1、定义参数

1 param($ProjectName$ProjectRootDirectory$KeystorePath$StorePass$KeyPass$Alias)
2 
3 $channels = @("360""aimi8""anzhi""appchina""eoemarket""gfan""hiapk""nduoa""starandroid")
4 $defaultChannel = "androidmarket"
5 $jdkPath = "E:\Program Files\Java\jdk1.7.0_01"
6 $androidSDKPath = "E:\Program Files\Android\android-sdk"
7 $signedPath = "$ProjectRootDirectory\bin\signed"
8 $zipalignedPath = "$ProjectRootDirectory\bin\zipaligned"
  • $ProjectName:项目名称,如:MyApp
  • $ProjectRootDirectory:项目路径,如:D:\workspace\MyApp
  • $KeystorePath:keystore路径,如:D:\workspace\MyApp\keystore
  • $StorePass:store password,如:123456
  • $KeyPass: key password,如:123456
  • $Alias: keystore alias,如:MyApp
  • $channels:定义了除AndroidManifest.xml中定义的默认市场标识外,剩下的所有市场标识
  • $defaultChannel:即上面提到的默认市场标识,为什么要有默认市场标识的原因是,我们的AndroidManifest.xml文件不会常改,我们也不希望每次自动编译、签名完毕后,看到这个文件处于被修改的状态,所以我设计在最后才给默认的市场编译,这样的话,前面修改了n次的AndroidManifest.xml在最后回到未修改的状态
  • $signedPath:即签好名的apk文件存储路径
  • $zipalignedPath:即zipalign优化后文件存储路径,最后要发布的也是这个目录下的apk文件

2、修改 AndroidManifest.xml

1 $manifestPath = "$ProjectRootDirectory\AndroidManifest.xml"
2 $FILE = [System.IO.File]::ReadAllText($manifestPath)
3 $FILE = [REGEX]::replace($FILE, '<meta-data\r?\n?\s+android:name="UMENG_CHANNEL"\r?\n?\s+(.*?)>', '<meta-data
4             android:name="UMENG_CHANNEL"
5             android:value="' + $ChannelName + '" />', [Text.regularexpressions.regexoptions]::SingleLine)
6 [System.IO.File]::WriteAllText($manifestPath$FILE)

$ChannelName 代表每次遍历传入的市场标识,如:anzhi

3、调用 build.bat 编译 项目

1 & "$ProjectRootDirectory\build"

4、为编译好的应用签名

1 & "$jdkPath\bin\jarsigner" -keystore $KeystorePath -storepass $StorePass -keypass $KeyPass -signedjar "$signedPath\$ProjectName-$ChannelName.apk" -verbose "$ProjectRootDirectory\bin\$ProjectName-release-unsigned.apk" $Alias -digestalg SHA1 -sigalg MD5withRSA 

  • 注意最后2个参数:-digestalg SHA1 -sigalg MD5withRSA,如果你当前的环境是 JDK 7,一定要加上这两个参数,否则签名完毕的应用在安装时会有错误:Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES] [1]
  • 签好名的应用在 $signedPath 定义的路径中

5、zipalign优化签好名的apk

1 if (Test-Path -path "$zipalignedPath\$ProjectName-$ChannelName.apk") {
2     Remove-Item "$zipalignedPath\$ProjectName-$ChannelName.apk"
3 }
4     
5 & "$androidSDKPath\tools\zipalign" -v 4 "$signedPath\$ProjectName-$ChannelName.apk" "$zipalignedPath\$ProjectName-$ChannelName.apk"

6、批处理调用powershell脚本,实现自动化编译、签名

假设powershell脚本存储于:D:\workspace\build4DifferentChannels.ps1,新建批处理脚本:D:\workspace\build4DifferentChannels_MyApp.bat:

1 powershell D:\workspace\build4DifferentChannels.ps1 MyApp "D:\workspace\MyApp" "D:\workspace\MyApp\keystore" 123456 123456 myapp

用批处理调用powershell脚本build4DifferentChannels.ps1,并传入了之前定义的各个参数。以后需要发布应用时,就执行该批处理,自动为各个市场编译、签名应用即可,十分方便。

如果执行改脚本遇到错误:

    File D:\workspace\build4DifferentChannels.ps1 cannot be loaded because the execution of scripts is disabled on this system. 

就用管理员权限打开command窗口,执行下面的命令:

1 powershell
2 Set-ExecutionPolicy RemoteSigned 

7、完整脚本下载

build4DifferentChannels_20111209.zip

参考 

[1]:http://code.google.com/p/android/issues/detail?id=19567

[2]:http://www.androidengineer.com/2010/06/using-ant-to-automate-building-android.html

广告

给最近开发的两个应用打一下广告

更新 

  • 2011-11-28
    谢谢wanx的提醒:<project name="xxx" default="help">,这里的xxx不是随便写,而是和使用eclipse手动编译出来的apk文件名一致,如果eclipse编译的文件名是Abc.apk,那么build.xml这段就应该改为:<project name="Abc" default="help"> 
  • 2011-12-02
    再次谢谢wanx的提醒:如果项目中有引用的第三方jar包类库,要把这些类库放到项目根目录的 "libs" 目录下,否则,ant在编译的时候会出错。
  • 2011-12-07
    加入zipalign优化脚本
  • 2011-12-09
    在zipalign之前,先删除旧有apk文件
posted @ 2011-11-23 19:44 朱博 阅读(1376) 评论(5) 编辑

2011年7月6日 #

JSONProtocol Buffers同为序列化数据的存储格式。

 

性能比较,视平台、语言、数据结构复杂程度的不同,Protocol Buffers与JSON相比,性能可能会从慢15倍到快5倍。值得指出的是,在Android系统中,Protocol Buffers反序列化数据会比JSON快大约3倍[1]

 

JSON数据格式有一个缺点:冗余太大,如:

 

[{"Name""Jane""Gender"0}, {"Name""Waith""Gender"1}]

 

每一条数据都要包括"Name"与"Gender",据统计,JSON格式的数据至少有1/5是无效的。

 

与JSON不同,Protocol Buffers用二进制编码数据,而且数据的格式是事先通过一个后缀名为.proto的文件指定的,如:

 

message Person {
  required string Name 
= 2;
  optional int32 Gender 
= 3;
}

 

这样Protocol Buffers的数据会比JSON小不少,在一些场景,比如内存里要存储更多的数据时,用Protocol Buffers会更合适[2]

 

参考:

[1], Serializing Data - JSON vs. Protocol Buffers

 

[2], 构建高性能的微博系统——再谈新浪微博架构

 

posted @ 2011-07-06 09:44 朱博 阅读(312) 评论(2) 编辑

2010年4月16日 #

时间往往在不经意间就浪费掉了,比如我们在寻找上一个光标位置的时候,好好学习并利用下面的技巧,会提高工作效率,减少不必要浪费的时间,提高时间利用率,让生活更加美好。

1,回到上一个光标位置

使用组合键 Ctrl + - 键表示Navigate BackWard, 使用组合键 Ctrl + Shift + - 键表示 Forward. 

2,删除多余的using指令,并且排序

当我们新一个类的时候,Visual Studio 会将常用的命名空间using在类的头部。但是在我们写完一个类的时候,有些using是多余的,删除多余的using,再排一下序,可以使代码看起来更清晰。Visual Studio 2008 已经为我们做好了这一切。在代码编辑区点击右键,可以看到"组织 using"菜单,这就是我们需要的了。

3,复制或删除一行代码时,不用先选择它

如果你想复制一行代码,你只需要简单的按CTRL+c拷贝,然后按CTRL+v粘贴这行就可以了,而不需要选择整行的代码。如果你想删除一行代码,只需按CTRL+x就可以了。

4,取代其他编辑器里Ctrl+F的方便的增量查找

用过ultraedit会对那两个上下搜索按钮印象深刻,Visual studio里有更厉害的。
操作方法:
1).按Ctrl+I键;
2).键入你要搜索的文本。注意:这时你会看到光标跳至第一个匹配的地方,匹配的文本高亮显示;
3).再次按下Ctrl+I键,光标将跳至下一个匹配的文本;
4).按Ctrl+Shift+I可向后搜索;
5).要停止搜索,按ESC键;

5,如何在编辑器中进行框式选择

操作方法:
你是否知道VS提供了两种不同的选择模型:流式和框式吗?
大家应该都熟悉流式选择模型了,只要使用Shift+方向键即可(或者使用鼠标进行选择)。
框式选择则允许你同时对航和列进行选择。只要同时按下Shift+Alt+方向键,你就了解它的不同之处了。剪切,拷贝,粘贴,这些功能都能使用,只是需要记住从哪里开始选择的。啊,让我想起了那段做测试时的时光。
备注:也可以使用鼠标+Alt键完成该操作。前两天我还遇到该提示的一个有意思的用法。有时候我们拷贝网上的文章中的代码时会将行号一起拷进来,使用框式选择可以只选择行号部分,将其删除。

6,如何使用快捷键在当前代码行的上面或下面插入一行(推荐,很实用)

按下Ctrl+Enter会在上面插入一个空行,Ctrl+Shift+Enter则会在下面插入一个空行。光标会移至新行的开始处。
备注:这是我非常喜欢的一个快捷键,如果不用这个,则需要使用Home或End,然后使用方向键,再使用回车才能达到上面的效果。

7,安装之后,将您的IDE设置恢复到默认设置

如果IDE的设置在任何先前发布的版本中做了更改,它们都应该被恢复到默认设置。可以在Visual Studio 2008中点击菜单 Tools > Import and Export Settings... > Reset all settings,此外还有一些Import和Export的选项可用。

8,通过按"tab"两次插入代码块

操作步骤:
在编辑的中输入代码片段,比如"for"

在这个状态下,按两次"tab"键,将会插入代码块,如下图所示

此时你可以把第一"i"改成"j",然后按Tab键,则所有的变量都变成了"j"。
备注:这样既快又不容易语法出错。

9,使用Ctrl+Tab打开IDE的导航,获得鸟瞰视图

同时在Visual Studio中导航到所有打开的文件和工具窗体
按"Ctrl+Tab"键,打开IDE导航窗口,按住Ctrl键,同时用方向键或鼠标选中一个文件或工具窗体来激活。

备注:这时最好不要松开"Ctrl+Tab",按方向键看鸟瞰图,全部松开后就定位到需要的文件或工具窗体,说实在的,这窗口挺酷的。

10,查找匹配的标记

某些标识总是成对出现。例如,"{"标识必须用对应的"}"标识关闭。虽然你点击一个{ 和它匹配的}就会高亮显示,但是如果代码过长的话就不好找了,同样,编译器指示符"#region"必须有对应的"#endregion"指示符。当导航你的代码时,你有时需要查找对应的标识。通过按Ctrl-]你可以这样做。这个快捷键只有当光标在这些标识符的任何一个的下面时才起作用,它会立即跳转到对应的标识符而不管它是开的或闭的标识。
如果你想显亮两个匹配的标识之间的所有代码时,按Ctrl-Shift-]显亮整个块,并移动光标到开的标识处。这个快捷键只有当光标在任意的标识的下面时才起作用(如光标在区域内它就不会起作用了)。
posted @ 2010-04-16 17:58 朱博 阅读(660) 评论(1) 编辑

2010年3月5日 #

该批处理可以考虑到例如4月1日前一天是3月31日,而不是4月0日的问题,值得参考。

 
@echo off
:: 作者: namejm  出自:cn-dos
:: 求N天前的日期
:: 日期可以带星期,但是,必须以年月日的顺序排列
:: 年份必须是四位,否则会出错
@echo off
:Main
cls
set day
=%date%
set days
=0
echo.
&echo.
echo       当前日期是:
%day%
echo.
&set /p input=      请指定要追溯的天数:
setlocal enabledelayedexpansion
:: 提取日期
for /"tokens=1-3 delims=-/. " %%in ("%day%"do (
    set 
/a sy=%%i, sm=100%%%% 100, sd=100%%%% 100
)
set 
/a sd-=input
if %sd% leq 0 call :count
cls
&echo.&echo.
echo       当前日期是:
%day%
echo.
set sm
=0%sm%
set sd
=0%sd%
echo       
%input% 天前的日期是:%sy%-%sm:~-2%-%sd:~-2%
pause
>nul
goto Main

:count
set 
/a sm-=1
if !sm! equ 0 set /a sm=12, sy-=1
call :days
set 
/a sd+=days
if %sd% leq 0 goto count
goto :eof

:days
:: 获取指定月份的总天数
set 
/a leap="^!(sy %% 4) & ^!(^!(sy %% 100)) | ^!(sy %% 400)"
set 
/a max=28+leap
for /"tokens=%sm%" %%in ("31 %max% 31 30 31 30 31 31 30 31 30 31"do set days=%%i
goto :eof

 

原文链接:http://bbs.verybat.org/viewthread.php?tid=11441

posted @ 2010-03-05 17:19 朱博 阅读(308) 评论(0) 编辑

2010年3月2日 #

前言

SQLServer2008中如何收缩日志文件,在邀月工作室的日志已经详细描述(点击查看),这里不再赘述。本文的重点是与大家分享日志截断、收缩后,物理文件的尺寸依然没有减小到期望尺寸的问题。

解决方案

我的一个数据库,数据文件10+G ,事务日志达20+G,而且使用常规的截断、收缩方法均无法减小日志物理文件的尺寸,经过一番寻找,终于找到了解决方法。

查看日志信息 

在查询分析器中执行如下代码来查看日志信息:

1 DBCC LOGINFO('数据库名称'

 我们看到status=0的日志,代表已经备份到磁盘的日志文件;而status=2的日志还没有备份。当我们收缩日志文件时,收缩掉的空间其实就是status=0的空间,如果日志物理文件无法减小,这里一定能看到非常多status=2的记录。接下来分析为什么会有这么多status=2的记录

查看日志截断延迟原因

活跃(active)的日志无法通过收缩来截断,有各种原因会使日志截断延迟,具体表现就是事务日志的物理文件无法通过截断、收缩来减小,通过下面的代码可以看到实例上每个数据库的日志截断延迟原因:

1 USE [master]
2 SELECT [name] ,[database_id] ,[log_reuse_wait] ,[log_reuse_wait_desc] FROM [sys].[databases]

各种原因及解释如下:

log_reuse_wait_desc 值 说明

NOTHING

当前有一个或多个可重复使用的虚拟日志文件。

CHECKPOINT

自上次日志截断之后,尚未出现检查点,或者日志头部尚未跨一个虚拟日志文件移动(所有恢复模式)。

这是日志截断延迟的常见原因。有关详细信息,请参阅检查点和日志的活动部分

LOG_BACKUP

需要日志备份,以将日志的头部前移(仅适用于完整恢复模式或大容量日志恢复模式)。

ms345414.note(zh-cn,SQL.100).gif注意:
日志备份不会妨碍截断。

完成日志备份后,日志的头部将前移,一些日志空间可能变为可重复使用。

ACTIVE_BACKUP_OR_RESTORE

数据备份或还原正在进行(所有恢复模式)。

数据备份与活动事务的运行方式相同。数据备份在运行时,将阻止截断。有关详细信息,请参阅本主题后面的“数据备份操作与还原操作”部分。

ACTIVE_TRANSACTION

事务处于活动状态(所有恢复模式)。

  • 一个长时间运行的事务可能存在于日志备份的开头。在这种情况下,可能需要进行另一个日志备份才能释放空间。有关详细信息,请参阅本主题后面的“长时间运行的活动事务”部分。
  • 事务被延迟(仅适用于 SQL Server 2005 Enterprise Edition 及更高版本)。“延迟的事务 ”是有效的活动事务,因为某些资源不可用,其回滚受阻。有关导致事务延迟的原因以及如何使它们摆脱延迟状态的信息,请参阅延迟的事务

DATABASE_MIRRORING

数据库镜像暂停,或者在高性能模式下,镜像数据库明显滞后于主体数据库(仅限于完整恢复模式)。

有关详细信息,请参阅本主题后面的“数据库镜像与事务日志”部分。

REPLICATION

在事务复制过程中,与发布相关的事务仍未传递到分发数据库(仅限于完整恢复模式)。

有关详细信息,请参阅本主题后面的“事务复制与事务日志”部分。

DATABASE_SNAPSHOT_CREATION

正在创建数据库快照(所有恢复模式)。

这是日志截断延迟的常见原因,通常也是主要原因。

LOG_SCAN

正在进行日志扫描(所有恢复模式)。

这是日志截断延迟的常见原因,通常也是主要原因。

针对延迟日志截断原因的部分解决方案

  • LOG_BACKUP
    备份日志后再执行收缩即可
  • REPLICATION
    这是我遇到的情况,但我根本没有启用过REPLICATION,据查,这好像是SQLSERVER2008的一个BUG,解决方法是给标有“REPLICATION”的数据库任意一个表创建数据库事务复制(TRANSACTION REPLICATION),然后再删除,执行数据库与日志备份后,就可以收缩了。

小技巧

一般收缩日志的代码中都要求指定日志的文件名称,下面的代码则可以自动获取日志文件名称:

1 USE [数据库名称]
2 DECLARE @LogFileLogicalName sysname
3 SELECT @LogFileLogicalName=Name FROM sys.database_files WHERE Type=1
4 PRINT @LogFileLogicalName
5 DBCC SHRINKFILE (@LogFileLogicalName1);

参考资料

  1. FAQ : How to truncate and shrink Transaction Log file in SQL Server
  2. 可能延迟日志截断的因素
  3. log_reuse_wait_desc = replication but there's no replication
  4. How to truncate Mirrored Database Log File
  5. SQL2008如何压缩日志(log)文件?
posted @ 2010-03-02 18:01 朱博 阅读(2498) 评论(1) 编辑

2009年11月20日 #

摘要: 前言今天凌晨(20091120)2:05左右,与Chrome技术交流QQ群(75448027)的朋友们一起聆听了远在美国的ChromeOS发布会,经过一番实验后,终于在自己PC的虚拟机中成功运行了ChromeOS。这篇文章旨在帮助所有对ChromeOS感兴趣的朋友一起实际体验一下ChromeOS,比看截图要更有趣一些。环境/准备 Windows XP/2003(其他版本未测试过,但不代表不可以使用...阅读全文
posted @ 2009-11-20 16:14 朱博 阅读(8770) 评论(38) 编辑

2009年9月14日 #

摘要: ReadWriteWeb最近推出了系列文章:“2009年互联网5大趋势”,第一个主要的趋势是结构化的数据,这个概念在以往有关语义网(Semantic Web)的一些演讲中,曾被引用过,但显而易见,到现在为止,结构化的数据比语义网的发展趋势更加明显。本文会分析结构化的数据在今年的发展,并且有三个产品供参考:OpenCalais, Google, Wolfram Alpha。阅读全文
posted @ 2009-09-14 00:45 朱博 阅读(2596) 评论(10) 编辑

2009年9月6日 #

摘要: 我写本文的目的,是和各位分享一下内容篡改式攻击的判断方法、SQL注入攻击的防范、以及被攻击后的补救(数据恢复)相关知识,如有谬误,期待您的指正。 * 如何在IIS6中安装WebKnight? * 如何配置WebKnight * 如何恢复被篡改的数据 * 如何找到有漏洞的程序阅读全文
posted @ 2009-09-06 23:14 朱博 阅读(4430) 评论(45) 编辑

2009年6月6日 #

摘要: 继去年参加了Google Developer Day 2008后,又迎来了Google Developer Day 2009,谢谢公司给我的时间,得以如愿参加这个技术盛宴。 技术的发展,往往迅雷不及掩耳。记得去年的GDD,谈到了云计算这个概念,经过了1年的发展,云计算的概念已经深入人心。去年谈到的App Engine、Google Maps API、Open Social、Android、iGoogle、Google Web Toolkit今年都有讲,这些技术都已经得到了更进一步的发展。值得注意的是,去年谈到的Gears,今年只字未提,这是因为今年的新技术:HTML5 其实已经可以替代Gears了。今年的重头戏是Google Wave,我知道最近在美国举行的2009 Google I/O大会上公布的Google Wave引起轰动,据说这是可以媲美Email发明的里程碑式的通讯工具。阅读全文
posted @ 2009-06-06 02:46 朱博 阅读(3330) 评论(33) 编辑

2009年3月4日 #

摘要: 一个服务ServiceA每5分钟会对配置好的网站首页、频道首页源地址分别发起一次请求,然后把请求的数据写入一个Html文档,这个Html文档即静态化的页面。 本来一直工作的很正常,但今天我使用了自定义的500错误页面后出问题了,首页静态页面不定时地呈现出了我自定义的500错误页面,经分析,发现原来没有使用自定义错误页面时,WebResponse的返回结果是一个错误,可以被捕捉到;但使用了自定义错误页面后,WebResponse就把这个错误页面当成了首页的内容了。阅读全文
posted @ 2009-03-04 18:24 朱博 阅读(568) 评论(0) 编辑