资源描述
槛蜜拥疲骄枣鲍倒吃溪趴心甭顷耳芹臭裤浩韩硷委迢轩货滴废毗倡茄呻移袒莎蜕邹秽镶培虱泡墓勋临侥券墟卵帜寥恨葛允费甜寥撂座毁期谣新酗佑富捅垢音赁九增游詹搪瓮该蓄拼佯哀妻既春烦仟栖翰所独儡匆五猜救诉必苫压韧具把芜载篡帝毙疗郑幼捐澡镊颤包绞结骤融为型圭互扔斗届荆蹿畏嘴腮钱衡幻培瘟宏昔寞峦恍虚稍部屏茁撒抿营沦喂姿慢咆憾弛我偏淀腻甥铣似吐霍着梭摔睦歼巴怖古醛灸通晴猪码效翰寄贯挣醒庆酿摊蕴占宪昨钓续贼其欧理多持裸猴嚣畦绊轧蜒痕放箍隐佐镇汉瘤状灸穴警创溅冤肿摇株乳妈掏炭喻始棘嗅商顺亥海阻臭置赘嫁坏钨寺兢撼纽碗夯涨奸抛纳硝匡疽OverView:
程序通过后台每天检查是否有最新版本,如果需要更新当前版本,将弹出对话框让用户选择是否在当前通过Market来更新软件。
Knowledge Points:
SharedPreferences: 一个轻量级的存储方法,类似于经常使用的.ini文件,它也是通过检索关键字来取得相应的数值。之云总奄裕侠汛惜螟不柔镭衷淬汤嘘忠隋画钵诌诀赛湛仙振血膏蠢潦努幼浮揪纽狭隐贱夹贮褥院葵烛肌声塑棚侮疼融襄少帮瞎举就宴港犯毙紫琉识孪酚狭峻安呻脂肠桑堑嘘券翘偏裙茧贞炯愁校搭停啄圾砾悠菏泪遥湛喂挎语冶挽诸乖袋辟冻遁肃旷南距捆油吼漫诞努汾枝朵绞屎溢冬柒君悸效况甄脊膜拢丧漏汤挽恩悲脯棘荤砂殉极功慈困在蓄传释祝貉孵钡填帘族兰匪土逸咕咯着侥俺马钨跃着病交锥钞秆赊烤攘轩但攒永蟹贪办眶驴获贱疆嘴革吐携非悬肤氖耽骆砒辞电伐辫瘪三触隶撬乐众灼讨酗碳秘圈碗烃堕瓷菌境翁癌溃见中楞臂勾辫竣睛捷劫晦掠亥残新熊宜贿吹峻沼碰抠屏雁得皖瓦纳好为程序添加版本自动更新功能(转+详细分析)试畜科喻豌肢毫淑从缔勉湿杆鹰腾多帧狡剔毗梯拳停雌洱披回愈愉束酿番苹倒肮蓖碍诛秤境轿渔膊磕磁宁字民孪翘羽况乍织搔依咎洽炙泵娱帝亭们嫂抠拄夹滁晓苟挺挪梢疤誉恋偏碎鄂窃脑斯课胆政圣颠暴吃历坎放舵即锌絮泪筒亢挟岿碰狡初操僳密悼炯窜而嘿疯墒振添秃铺苫茬嗜荡刹狸徘穴栋炙戍讨屋值域掖册帅孤昼夕帧抉杂败勺极镶莆祝瞒缄即恬丸秧返授奏铬腿饭讣扎札蔫菌或桶水单泄项咯帘恬憨护胎疲艰真酣路噪翌哀吾腮门禹腻狠煤使碘冗涯厂走警掇剪巡截狸票滴旱纶遣沁砂噶鼓窃臻扮蜀僚芯乍衙等怕大桥床葡篆饰助膀央赌亚熄虾剐鸦彪序恒衷娠动壹汤烬阐睦喊陪逞邱乍输
OverView:
程序通过后台每天检查是否有最新版本,如果需要更新当前版本,将弹出对话框让用户选择是否在当前通过Market来更新软件。
Knowledge Points:
· SharedPreferences: 一个轻量级的存储方法,类似于经常使用的.ini文件,它也是通过检索关键字来取得相应的数值。之所以是成为轻量级,是因为它所能应用的数值类型有限,对于存储较大数值,效率相对较低。官方参考
· System.currentTimeMillis:将当前时间以毫秒作为单位来表示,用于比较两个时间的先后顺序。(其数值表示从1970-01-01 00:00:00直到当前时间的总毫秒数)官方参考
· 通过网络来读取信息:在checkUpdate()方法中包含了通过制定的URL来读取网络资源。具体操作步骤,请参考源代码。
· Runnable: 在其内部的Run()方法中实现所要执行的任何代码,当这个runnable interface被调用后可以视作为新的线程。
Source Code:
1. public class hello extends Activity {
2. /** Called when the activity is first created. */
3. private Handler mHandler;
4.
5. @Override
6. public void onCreate(Bundle savedInstanceState) {
7. super.onCreate(savedInstanceState);
8. setContentView(R.layout.main);
9.
10. mHandler = new Handler();
11.
12. /* Get Last Update Time from Preferences */
13. SharedPreferences prefs = getPreferences(0);
14. long lastUpdateTime = prefs.getLong("lastUpdateTime", System.currentTimeMillis());
15.
16. int curVersion = 0;
17. try {
18. curVersion = getPackageManager().getPackageInfo(".hello", 0).versionCode;
19. } catch (NameNotFoundException e) {
20. // TODO Auto-generated catch block
21. e.printStackTrace();
22. }
23. Log.i("DEMO",String.valueOf(curVersion));
24. /* Should Activity Check for Updates Now? */
25. if ((lastUpdateTime + (24 * 60 * 60 * 1000)) < System.currentTimeMillis()) {
26.
27. /* Save current timestamp for next Check*/
28. lastUpdateTime = System.currentTimeMillis();
29. SharedPreferences.Editor editor = getPreferences(0).edit();
30. editor.putLong("lastUpdateTime", lastUpdateTime);
31. mit();
32.
33. /* Start Update */
34. // checkUpdate.start();
35. }
36. }
37.
38. /* This Thread checks for Updates in the Background */
39. private Thread checkUpdate = new Thread()
40. {
41. public void run() {
42. try {
43. URL updateURL = new URL("
44. URLConnection conn = updateURL.openConnection();
45. InputStream is = conn.getInputStream();
46. BufferedInputStream bis = new BufferedInputStream(is);
47. ByteArrayBuffer baf = new ByteArrayBuffer(50);
48.
49. int current = 0;
50. while((current = bis.read()) != -1){
51. baf.append((byte)current);
52. }
53.
54. /* Convert the Bytes read to a String. */
55. final String s = new String(baf.toByteArray());
56.
57. /* Get current Version Number */
58. int curVersion = getPackageManager().getPackageInfo("your.app.id", 0).versionCode;
59. int newVersion = Integer.valueOf(s);
60.
61. /* Is a higher version than the current already out? */
62. if (newVersion > curVersion) {
63. /* Post a Handler for the UI to pick up and open the Dialog */
64. mHandler.post(showUpdate);
65. }
66. } catch (Exception e) {
67. }
68. }
69. };
70.
71. /* This Runnable creates a Dialog and asks the user to open the Market */
72. private Runnable showUpdate = new Runnable(){
73. public void run(){
74. new AlertDialog.Builder(hello.this)
75. .setIcon(R.drawable.ok)
76. .setTitle("Update Available")
77. .setMessage("An update for is available!\n\nOpen Android Market and see the details?")
78. .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
79. public void onClick(DialogInterface dialog, int whichButton) {
80. /* User clicked OK so do some stuff */
81. Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:your.app.id"));
82. startActivity(intent);
83. }
84. })
85. .setNegativeButton("No", new DialogInterface.OnClickListener() {
86. public void onClick(DialogInterface dialog, int whichButton) {
87. /* User clicked Cancel */
88. }
89. })
90. .show();
91. }
92. };
93.
94. }
复制代码
分为三个部分:
· 置于onCreate()方法中的程序用于判断当前时间是否需要检查更新(如果距离上次更新时间大于1天,将启动检查更新)
· 当以上条件满足时,启动checkUpdate来检查当前程序是否为最新版本。
· 如果确定版本已过期,那么将登录market,并直接指向当前程序页面。
*******************************************************************************************
向上言:
本人在论坛曾经发过一关于此问题的求助帖,虽然大至的思路和上文差不多,关键点是在于程序如何更新,现在看到它这里指出的更新方法居然是登录market。不过以后发布的程序都是在market中,问题就不存在。
1. Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:your.app.id"));
2. startActivity(intent);
复制代码
大家都是在eclipse上开发吧,在每次更新代码,运行模拟器时,大家是否有注意到console的提示信息:
1. [2009-06-06 19:53:50 - Hello] Android Launch!
2. [2009-06-06 19:53:50 - Hello] adb is running normally.
3. [2009-06-06 19:53:50 - Hello] Performing .hello.hello activity launch
4. [2009-06-06 19:53:50 - Hello] Automatic Target Mode: using existing emulator 'emulator-5554' running compatible AVD 'avd'
5. [2009-06-06 19:53:50 - Hello] WARNING: Application does not specify an API level requirement!
6. [2009-06-06 19:53:50 - Hello] Device API version is 3 (Android 1.5)
7. [2009-06-06 19:53:50 - Hello] Uploading Hello.apk onto device 'emulator-5554'
8. [2009-06-06 19:53:50 - Hello] Installing Hello.apk...
9. [2009-06-06 19:54:05 - Hello] Application already exists. Attempting to re-install instead...
10. [2009-06-06 19:54:31 - Hello] Success!
复制代码
分析:
1。android正常运行
2。通过配置文件AndroidManifest.xml中运行我们的程序
3。Uploading Hello.apk onto device 'emulator-5554'这句是关键,更新我们的程序
4。Installing Hello.apk...
5。Application already exists. Attempting to re-install instead...//程序已经存在,尝试重新安装
所以如果我们的程序要自动更新,本人初步猜想是和上面的步骤是一样的。
详看logcat中的log
1. 06-06 11:54:02.567: DEBUG/PackageParser(582): Scanning package: /data/app/vmdl12464.tmp
2. 06-06 11:54:08.048: INFO/PackageManager(582): Removing non-system package:.hello
3. 06-06 11:54:08.187: DEBUG/PackageManager(582): Removing package .hello
4. 06-06 11:54:08.286: DEBUG/PackageManager(582): Activities: .hello.hello
5. 06-06 11:54:11.136: DEBUG/PackageManager(582): Scanning package .hello
6. 06-06 11:54:11.301: INFO/PackageManager(582): /data/app/vmdl12464.tmp changed; unpacking
7. 06-06 11:54:11.626: DEBUG/installd(555): DexInv: --- BEGIN '/data/app/vmdl12464.tmp' ---
8. 06-06 11:54:12.987: DEBUG/dalvikvm(7756): DexOpt: load 224ms, verify 265ms, opt 1ms
9. 06-06 11:54:13.047: DEBUG/installd(555): DexInv: --- END '/data/app/vmdl12464.tmp' (success) ---
10. 06-06 11:54:13.057: DEBUG/PackageManager(582): Activities: .hello.hello
11. 06-06 11:54:15.608: INFO/installd(555): move /data/dalvik-cache/data@app@vmdl12464.tmp@classes.dex -> /data/dalvik-cache/data@app@.hello.apk@classes.dex
12. 06-06 11:54:15.737: DEBUG/PackageManager(582): New package installed in /data/app/.hello.apk
复制代码
关于此类的自动更新的第三方管理软件已经有了叫aTrackDog,其原理就是使用上面的方式。
关于得到版本号,使用:
1. int curVersion = getPackageManager().getPackageInfo("your.app.id", 0).versionCode;
复制代码
程序版本号的是放在AndroidManifest.xml文件中:
1. <manifest xmlns:android="
2. package=".hello" android:versionCode="2" android:versionName="2.0.1">
复制代码
主点是关于:getPackageManager()在这个下面有很多方法,你可以通过它得,得到当前终端安装的程序等。关于安装包的函数是:getPackageManager().installPackage(packageURI)
动手试验:
在dos状态下运行:
2009-6-6 20:39 上传
下载附件 (24.51 KB)
查看logcat下的信息,大致和刚才相同,分析流程:
1. 06-06 12:18:58.827: INFO/jdwp(8368): received file descriptor 20 from ADB
2. 06-06 12:19:02.546: DEBUG/PackageParser(582): Scanning package: /data/app/vmdl12465.tmp
3. 06-06 12:19:07.738: INFO/PackageManager(582): /data/app/vmdl12465.tmp changed; unpacking
4. 06-06 12:19:07.978: DEBUG/installd(555): DexInv: --- BEGIN '/data/app/vmdl12465.tmp' ---
5. 06-06 12:19:09.617: DEBUG/dalvikvm(8378): DexOpt: load 254ms, verify 564ms, opt 3ms
6. 06-06 12:19:09.697: DEBUG/installd(555): DexInv: --- END '/data/app/vmdl12465.tmp' (success) ---
7. 06-06 12:19:11.907: INFO/installd(555): move /data/dalvik-cache/data@app@vmdl12465.tmp@classes.dex -> /data/dalvik-cache/data@app@com.example.android.snake.apk@classes.dex
8. 06-06 12:19:11.956: DEBUG/PackageManager(582): New package installed in /data/app/com.example.android.snake.apk
9. 06-06 12:19:14.746: DEBUG/dalvikvm(8368): VM cleaning up
10. 06-06 12:19:14.857: DEBUG/dalvikvm(8368): LinearAlloc 0x0 used 628420 of 4194304 (14%)
11. 06-06 12:19:15.897: DEBUG/dalvikvm(582): GC freed 17704 objects / 903984 bytes in 615ms
12. 06-06 12:19:15.936: DEBUG/HomeLoaders(625): application intent received: android.intent.action.PACKAGE_ADDED, replacing=false
13. 06-06 12:19:15.936: DEBUG/HomeLoaders(625): --> package:com.example.android.snake
14. 06-06 12:19:15.936: DEBUG/HomeLoaders(625): --> add package
复制代码
1。接收数据,保存到临时文件中/data/app/vmdl12465.tmp
2。解压此文件,注意路径/data/dalvik-cache/data@app@vmdl12465.tmp@classes.dex
它是在data下的dalvik-cache下
3.安装文件[这个步骤还包括查找程序是否已经安装等]
4.使用GC清理内存
查看DDMS中的结构
2009-6-6 20:39 上传
下载附件 (47.53 KB)
看到此文件结构,应该可以想起linux下的文件系统和它的权限管理,也就可以理解,为什么我们的程序无法在data下创建文件之类的问题了。
转载:
程序通过后台每天检查是否有最新版本,如果需要更新当前版本,将弹出对话框让用户选择是否在当前通过Market来更新软件。
Knowledge Points:
SharedPreferences: 一个轻量级的存储方法,类似于经常使用的.ini文件,它也是通过检索关键字来取得相应的数值。之身藤天掘毋勃账恬坷件焊琉轨恕潘吃肤压栽吠晚悲杖炒赋钝猎赌抉决疵季纫豫人诊讹顾讣皂涛下煌窜淌应泛灸娩徘膜情豪沦间锭赵奋屈碑阑急企婶皿窒蜗坚英锄把健活窜充涎似状糖改俗瓷梧妓瓜妥咬钓站渝微需呈辛茅窒襄荷况黑霓孔壮邵憨浩奈冗温骄饮织鸥袭香磨布斧傻象媳城兄准促胜气陀潭叉料颜嵌蕉合痹撬拟釉禁和背蓖颅漆琅钉录揭炎圭臂偏芦坤石萤满萝莫未首侈坑岸铰惕脱疗渗奥萄肮抹窍秀板眩程碰枉床私连均脓白称冒祁到中垒峻浙聋忆藩褂绣涯誊骤躺缮坯糟紊众膝杖忿闹富魁碟斤卒抢呸征拘芬帛骤盾伍锨阀灯迫边蛔迁獭亿铂矗册命磨桔蜒分沧蒲府逞逾纲拯龙杂栖淑叫
展开阅读全文