由于Android项目开源所致,有很多安卓软件市场。为了让我们开发的软件有更多的用户使用,我们需要向很多市场发布,软件升级后,我们也必须到安卓市场上进行更新,给我们增加了工作量。因此我们有必要给我们的Android应用增加自动更新的功能。那么实现自动更新,我们首先必须让我们的应用知道是否存在新版本的软件,因此我们可以在自己的网站上放置配置文件,存放软件的版本信息:

下面就续上本次知识点的相关内容:

(1)需要解析的xml文件:update.xml文件,此文件放置在服务器上:


1. <?xml version="1.0" encoding="utf-8"?>
2. <updates>
3. <update id="2">
4. <version>2</version>
5. <name>应用程序安装</name>
6. <url>http://10.0.1.163/shine/one.apk</url>
7. </update>
8. </updates>


(2)在这里我们使用xml文件进行信息的读取,且由于xml文件比较小,故而此处可以通过DOM方式进行xml文件的解析

 

xml文件读取类:ParseXmlService.java


1. package
2.   
3. import
4. import
5. import
6. import
7. import
8. import
9.   
10. import
11. import
12.   
13. import
14. import
15. import
16. import
17.   
18. import
19.   
20. public class
21.   
22. public List<HashMap<String, String>> getContactAll() throws
23. null;  
24. "http://10.0.1.163/shine/update.xml";  
25. new
26.         HttpURLConnection conn = (HttpURLConnection) url.openConnection();  
27. 3000);  
28. "GET");  
29. if
30.             InputStream is = conn.getInputStream();  
31. // 这里获取数据直接放在xmlpullparser里面解析;
32.             contacts = parseXml(is);  
33. 0).get("name")  
34. "======================================");  
35. 0).get("version")  
36. "======================================");  
37. 0).get("url")  
38. "======================================");  
39. return
40.         }  
41. return null;  
42.     }  
43.   
44. public
45. throws
46. new
47. null;  
48. // 实例化一个文档构建器工厂
49.         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();  
50. // 通过文档构建器工厂获取一个文档构建器
51.         DocumentBuilder builder = factory.newDocumentBuilder();  
52. // 通过文档通过文档构建器构建一个文档实例
53.         Document document = builder.parse(inStream);  
54. // 获取XML文件根节点
55.         Element root = document.getDocumentElement();  
56. // 获得所有子节点
57.         NodeList updates = root.getChildNodes();  
58. if (updates != null) {  
59. new
60. for (int i = 0; i < updates.getLength(); i++) {  
61.                 Node update = updates.item(i);  
62. if
63. "id")  
64.                             .getNodeValue();  
65. "+++++++id++++++"
66. "id", update.getAttributes().getNamedItem("id")  
67.                             .getNodeValue());  
68.   
69. for (Node node = update.getFirstChild(); node != null; node = node  
70.                             .getNextSibling()) {  
71. if
72. if (node.getNodeName().equals("version")) {  
73. // String name=node.getNodeValue();
74.                                 String name1 = node.getFirstChild()  
75.                                         .getNodeValue();  
76. "+++++++版本号++++++"
77. "version", node.getFirstChild()  
78.                                         .getNodeValue());  
79.   
80.                             }  
81. if (node.getNodeName().equals("name")) {  
82.                                 String price = node.getFirstChild()  
83.                                         .getNodeValue();  
84. "+++++软件名称++++++++"
85. "name", node.getFirstChild()  
86.                                         .getNodeValue());  
87.                             }  
88. if (node.getNodeName().equals("url")) {  
89.                                 String price1 = node.getFirstChild()  
90.                                         .getNodeValue();  
91.                                 System.out  
92. "++++++下载地址+++++++"
93. "url", node.getFirstChild()  
94.                                         .getNodeValue());  
95.                             }  
96.                         }  
97.   
98.                     }  
99.                 }  
100.   
101.             }  
102.             list.add(hashMap);  
103.         }  
104. return
105.   
106.     }  
107. }


通过该类我们获取到的versionCode对应AndroidManifest.xml下android:versionCode。android:versionCode和android:versionName两个属性分别表示版本号,版本名称。versionCode是整数型,而versionName是字符串。由于versionName是给用户看的,不太容易比较大小,升级检查时,就可以检查versionCode。把获取到的手机上应用版本与服务器端的版本进行比较,应用就可以判断处是否需要更新软件。

(3)检测更新与下载安装类

UpdateManager.java

1. package
2.   
3. import
4. import
5. import
6. import
7. import
8. import
9. import
10. import
11. import
12.   
13. import
14. import
15. import
16. import
17. import
18. import
19. import
20. import
21. import
22. import
23. import
24. import
25. import
26. import
27. import
28. import
29. import
30.   
31. public class
32. {  
33. /* 下载中 */
34. private static final int DOWNLOAD = 1;  
35. /* 下载结束 */
36. private static final int DOWNLOAD_FINISH = 2;  
37. /* 保存解析的XML信息 */
38.     HashMap<String, String> mHashMap;  
39.     List<HashMap<String, String>> list;  
40. /* 下载保存路径 */
41. private
42. /* 记录进度条数量 */
43. private int
44. /* 是否取消更新 */
45. private boolean cancelUpdate = false;  
46.   
47. private
48. /* 更新进度条 */
49. private
50. private
51.   
52. private Handler mHandler = new
53.     {  
54. public void
55.         {  
56. switch
57.             {  
58. // 正在下载
59. case
60. // 设置进度条位置
61.                 mProgress.setProgress(progress);  
62. break;  
63. case
64. // 安装文件
65.                 installApk();  
66. //install();
67. break;  
68. default:  
69. break;  
70.             }  
71.         };  
72.     };  
73.   
74. public
75.     {  
76. this.mContext = context;  
77.     }  
78.   
79. /**
80.      * 检测软件更新
81.      */
82. public void
83.     {  
84. if
85.         {  
86. // 显示提示对话框
87.             showNoticeDialog();  
88. else
89.         {  
90.             Toast.makeText(mContext, R.string.soft_update_no, Toast.LENGTH_LONG).show();  
91.         }  
92.     }  
93.   
94. /**
95.      * 检查软件是否有更新版本
96.      * 
97.      * @return
98.      */
99. public boolean
100.     {  
101. // 获取当前软件版本
102. int
103. // 把version.xml放到网络上,然后获取文件信息
104. //InputStream inStream = ParseXmlService.class.getClassLoader().getResourceAsStream("update.xml");
105. // 解析XML文件。 由于XML文件比较小,因此使用DOM方式进行解析
106. new
107. try
108.         {  
109. //mHashMap = service.parseXml(inStream);
110.             list=service.getContactAll();  
111. "=================");  
112.               
113. catch
114.         {  
115.             e.printStackTrace();  
116.         }  
117. if (null
118.         {  
119. //int serviceCode = Integer.valueOf(mHashMap.get("version"));
120. int serviceCode=Integer.valueOf(list.get(0).get("version"));  
121. "软件版本号码:======================================"+versionCode);  
122. // 版本判断
123. if
124.             {  
125. return true;  
126.             }  
127.         }  
128. return false;  
129.     }  
130.   
131. /**
132.      * 获取软件版本号
133.      */
134. private int
135.     {  
136. int versionCode = 0;  
137. try
138.         {  
139. // 获取软件版本号,对应AndroidManifest.xml下android:versionCode
140. "com.shine.update", 0).versionCode;  
141. catch
142.         {  
143.             e.printStackTrace();  
144.         }  
145. return
146.     }  
147.   
148. /**
149.      * 显示软件更新对话框
150.      */
151. private void
152.     {  
153. // 构造对话框
154. new
155.         builder.setTitle(R.string.soft_update_title);  
156.         builder.setMessage(R.string.soft_update_info);  
157. // 更新
158. new
159.         {  
160. @Override
161. public void onClick(DialogInterface dialog, int
162.             {  
163.                 dialog.dismiss();  
164. // 显示下载对话框
165.                 showDownloadDialog();  
166.             }  
167.         });  
168. // 稍后更新
169. new
170.         {  
171. @Override
172. public void onClick(DialogInterface dialog, int
173.             {  
174.                 dialog.dismiss();  
175.             }  
176.         });  
177.         Dialog noticeDialog = builder.create();  
178.         noticeDialog.show();  
179.     }  
180.   
181. /**
182.      * 显示软件下载对话框
183.      */
184. private void
185.     {  
186. // 构造软件下载对话框
187. new
188.         builder.setTitle(R.string.soft_updating);  
189. // 给下载对话框增加进度条
190. final
191. null);  
192.         mProgress = (ProgressBar) v.findViewById(R.id.update_progress);  
193.         builder.setView(v);  
194. // 取消更新
195. new
196.         {  
197. @Override
198. public void onClick(DialogInterface dialog, int
199.             {  
200.                 dialog.dismiss();  
201. // 设置取消状态
202. true;  
203.             }  
204.         });  
205.         mDownloadDialog = builder.create();  
206.         mDownloadDialog.show();  
207. // 现在文件
208.         downloadApk();  
209.     }  
210.   
211. /**
212.      * 下载apk文件
213.      */
214. private void
215.     {  
216. // 启动新线程下载软件
217. new
218.     }  
219.   
220. /**
221.      * 下载文件线程
222.      */
223. private class downloadApkThread extends
224.     {  
225. @Override
226. public void
227.         {  
228. try
229.             {  
230. // 判断SD卡是否存在,并且是否具有读写权限
231. if
232.                 {  
233. // 获得存储卡的路径
234. "/";  
235. "download";  
236. //  URL url = new URL(mHashMap.get("url"));
237. new URL(list.get(0).get("url"));  
238. "路径:"+list.get(0).get("url"));  
239. // 创建连接
240.                     HttpURLConnection conn = (HttpURLConnection) url.openConnection();  
241.                     conn.connect();  
242. // 获取文件大小
243. int
244. // 创建输入流
245.                     InputStream is = conn.getInputStream();  
246.   
247. new
248. // 判断文件目录是否存在
249. if
250.                     {  
251.                         file.mkdir();  
252.                     }  
253. new File(mSavePath, list.get(0).get("name"));  
254. new
255. int count = 0;  
256. // 缓存
257. byte buf[] = new byte[1024];  
258. // 写入到文件中
259. do
260.                     {  
261. int
262.                         count += numread;  
263. // 计算进度条位置
264. int) (((float) count / length) * 100);  
265. // 更新进度
266.                         mHandler.sendEmptyMessage(DOWNLOAD);  
267. if (numread <= 0)  
268.                         {  
269. // 下载完成
270.                             mHandler.sendEmptyMessage(DOWNLOAD_FINISH);  
271. break;  
272.                         }  
273. // 写入文件
274. 0, numread);  
275. while (!cancelUpdate);// 点击取消就停止下载.
276.                     fos.close();  
277.                     is.close();  
278.                 }  
279. catch
280.             {  
281.                 e.printStackTrace();  
282. catch
283.             {  
284.                 e.printStackTrace();  
285.             }  
286. // 取消下载对话框显示
287.             mDownloadDialog.dismiss();  
288.         }  
289.     };  
290.   
291. /**
292.      * 安装APK文件
293.      */
294. private void
295.     {  
296. new File(mSavePath, list.get(0).get("name"));  
297. if
298.         {  
299. return;  
300.         }  
301. // 通过Intent安装APK文件
302. new
303. "file://" + apkfile.toString()), "application/vnd.android.package-archive");  
304.         mContext.startActivity(i);  
305.     }  
306. private void
307. new
308.         PackageManager pm=mContext.getPackageManager();  
309. new File(mSavePath, list.get(0).get("name"));  
310. if
311.         {  
312. return;  
313.         }  
314.   
315. //      intent.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory(), "1.apk"))   
316. //              , "application/vnd.android.package-archive");   
317. "com.android.packageinstaller.applicationInfo",    
318. "/"+list.get(0).get("name"), PackageManager.GET_ACTIVITIES).applicationInfo);    
319. new
320. "com.android.packageinstaller", "com.android.packageinstaller.InstallAppProgress");    
321.       mContext.startActivity(intent);    
322.   
323.     }  
324. }


 

(4)主Activity类

 

1. package
2.   
3. import
4. import
5. import
6. import
7. import
8. import
9. import
10.   
11.   
12.   
13. public class MainActivity extends
14. {  
15.     Boolean flag;  
16.     UpdateManager manager;  
17. private Handler handler=new
18. public void
19. switch
20. case 123:  
21. // 检查软件更新
22.                 manager.checkUpdate();  
23. break;  
24.   
25. default:  
26. break;  
27.             }  
28.         }  
29.     };  
30. @Override
31. public void
32.     {  
33. super.onCreate(savedInstanceState);  
34.         setContentView(R.layout.main);  
35.         Button updateBtn = (Button) findViewById(R.id.btnUpdate);  
36. new UpdateManager(MainActivity.this);  
37. new
38.         {  
39. @Override
40. public void
41.             {  
42. new Thread(new
43.                       
44. @Override
45. public void
46. // TODO Auto-generated method stub
47.                         flag=manager.isUpdate();  
48. new
49. 123;  
50.                         handler.sendMessage(msg);  
51.                     }  
52.                 }).start();  
53.                   
54.             }  
55.         });  
56.    
57.     }  
58. }


 

(5)AndroidManifest.xml类


1. <?xml version="1.0" encoding="utf-8"?>
2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3. package="com.shine.update"
4. android:versionCode="1"
5. android:versionName="1.0" >
6.   
7. <uses-sdk
8. android:minSdkVersion="8"
9. android:targetSdkVersion="17" />
10.   
11. <uses-permission android:name="android.permission.INTERNET" />
12. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
13. <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
14. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
15. <application
16. android:allowBackup="true"
17. android:icon="@drawable/ic_launcher"
18. android:label="@string/app_name"
19. android:theme="@style/AppTheme" >
20. <activity
21. android:name="com.shine.update.MainActivity"
22. android:label="@string/app_name" >
23. <intent-filter>
24. <action android:name="android.intent.action.MAIN" />
25.   
26. <category android:name="android.intent.category.LAUNCHER" />
27. </intent-filter>
28. </activity>
29. </application>
30.   
31. </manifest>


 

(6)相关xml布局文件

softupdate_progress.xml


1. <?xml version="1.0" encoding="utf-8"?>
2. <LinearLayout
3. xmlns:android="http://schemas.android.com/apk/res/android"
4. android:layout_width="fill_parent"
5. android:layout_height="wrap_content">
6. <ProgressBar
7. android:id="@+id/update_progress"
8. android:layout_width="fill_parent"
9. android:layout_height="wrap_content"
10. style="?android:attr/progressBarStyleHorizontal" />
11. </LinearLayout>


main.xml



1. <?xml version="1.0" encoding="utf-8"?>
2. <LinearLayout
3. xmlns:android="http://schemas.android.com/apk/res/android"
4. android:orientation="vertical"
5. android:layout_width="fill_parent"
6. android:layout_height="fill_parent">
7. <Button
8. android:id="@+id/btnUpdate"
9. android:layout_width="match_parent"
10. android:layout_height="wrap_content"
11. android:text="更新"
12. />
13. </LinearLayout>


strings.xml



1. <?xml version="1.0" encoding="utf-8"?>
2. <resources>
3.   
4. <string name="app_name">应用程序自动更新</string>
5. <string name="hello_world">Hello world!</string>
6. <string name="menu_settings">Settings</string>
7.   
8. <string name="soft_update_no">已经是最新版本</string>
9. <string name="soft_update_title">软件更新</string>
10. <string name="soft_update_info">检测到新版本,立即更新吗</string>
11. <string name="soft_update_updatebtn">更新</string>
12. <string name="soft_update_later">稍后更新</string>
13. <string name="soft_updating">正在更新</string>
14. <string name="soft_update_cancel">取消</string>
15. </resources>


android app自动更新安装失败 安卓 应用自动更新_java

综述:对于此软件更新,还可以进行改进的地方,如在下载apk 的时候进行多线程进行下载,即断点进行下载,即使网络性能不好,也可以继续进行下载,进而以此节约流量,

另外,还有在apk安装的时候,这个地方也是一个知识点,就静默安装,还是需要操作安装呢?

最后下载完毕后,可以在sdcard/down文件夹下面看到所下载的apk文件

 

自动安装apk的例子:


1. Intent intent = new
2. //        intent.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory(), "1.apk"))   
3. //                , "application/vnd.android.package-archive");   
4. "com.android.packageinstaller.applicationInfo",    
5. "/sdcard/1.apk", PackageManager.GET_ACTIVITIES).applicationInfo);    
6. new File(Environment.getExternalStorageDirectory(), "1.apk")));    
7. "com.android.packageinstaller", "com.android.packageinstaller.InstallAppProgress");    
8.         startActivity(intent);


上面代码能实现直接安装程序,不需要点击确定、安装的。需要系统权限,在AndroidMainifest.xml文件中添加android:sharedUserId="android.uid.system"加了上句后程序将会装不上机器,需要给程序签名。

 

==============

1.打开程序

PackageManager pm=getPackageManager();

Intent intent=new Intent();

   intent=pm.getLaunchIntentForPackage("此处写要打开的程序的包名");
   startActivity(intent);

第二种打开方式:

    ComponentName cn =new ComponentName(“此处填包名”, “此处填 包名.启动类名”);
    Intent intent = new Intent(Intent.ACTION_MAIN);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
    intent.setComponent(cn);
    startActivity(intent);

打开程序命令:am start -n com.android.settings/com.android.settings.Settings

其中com.android.settings/com.android.settings.Settings 指 包名/启动类名

2.卸载程序

    Intent intent=new Intent(Intent.ACTION_DELETE,Uri.parse("package:"+此处为要卸载的程序的包名));
    context.startActivity(intent);