• [置顶] Android应用开发之版本更新你莫愁


    传送门 ☞ 轮子的专栏 ☞ 转载请注明 ☞ http://blog.csdn.net/leverage_1229

            今天我们学习如何实现Android应用的自动更新版本功能,这是在各种语言编写的应用中都会经常遇到的情景。当我们的应用检测到网络上有新版本发布时,系统会提示是否下载新版本应用,当新版本应用下载完毕后,系统会自动安装下载的新版本应用(或跳转到相关安装页面询问)。我们将下载的应用存放在sdcard中,由于整个流程涉及对sdcard的读写操作,所以要赋给我们应用读写外存的权限。下面给出该场景的案例:

    一、案例技术要点

    1.程序清单文件中需要配置如下权限:

    访问网络

    1. <uses-permission android:name="android.permission.INTERNET"/>  
    读取sdcard
    1. <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>  
    写入sdcard
    1. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>  

    2.创建一个HttpURLConnection连接,从网络下载新版本应用到本地

    3.创建一个ProgressBar下载进度条,实时显示下载应用的进度

    4.应用下载完毕后,构建Intent跳转至其安装页面,该Intent的配置如下:

    Action:Intent.ACTION_VIEW

    DataAndType:Uri.parse("file://" + appFile.toString()),"application/vnd.android.package-archive"

    二、案例代码陈列

    AndroidManifest.xml

    1. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
    2.     package="cn.lynn.autoupdate"  
    3.     android:versionCode="1"  
    4.     android:versionName="1.0" >  
    5.   
    6.     <uses-sdk  
    7.         android:minSdkVersion="8"  
    8.         android:targetSdkVersion="15" />  
    9.     <uses-permission android:name="android.permission.INTERNET"/>  
    10.     <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>  
    11.     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>  
    12.     <application  
    13.         android:icon="@drawable/ic_launcher"  
    14.         android:label="@string/app_name" >  
    15.         <activity  
    16.             android:name=".AutoUpdateMainActivity"  
    17.             android:label="@string/app_name" >  
    18.             <intent-filter>  
    19.                 <action android:name="android.intent.action.MAIN" />  
    20.   
    21.                 <category android:name="android.intent.category.LAUNCHER" />  
    22.             </intent-filter>  
    23.         </activity>  
    24.     </application>  
    25.   
    26. </manifest>  
    strings.xml
    1. <resources>  
    2.     <string name="app_name">Android实现应用自动更新</string>  
    3. </resources>  
    main.xml
    1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    2.     android:layout_width="match_parent"  
    3.     android:layout_height="match_parent" >  
    4.   
    5.     <TextView  
    6.         android:layout_width="wrap_content"  
    7.         android:layout_height="wrap_content" />  
    8.   
    9. </LinearLayout>  
    下载进度条布局文件:progressBar.xml
    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     android:layout_width="match_parent"  
    4.     android:layout_height="wrap_content">  
    5.   
    6.     <ProgressBar   
    7.         android:id="@+id/progressBar"  
    8.         style="?android:attr/progressBarStyleHorizontal"  
    9.         android:layout_width="match_parent"  
    10.         android:layout_height="wrap_content" />  
    11.   
    12. </LinearLayout>  
    AutoUpdateMainActivity.java
    1. package cn.lynn.autoupdate;  
    2.   
    3. import android.app.Activity;  
    4. import android.os.Bundle;  
    5.   
    6. public class AutoUpdateMainActivity extends Activity {  
    7.     private UpdateAppManager updateManager;  
    8.   
    9.     @Override  
    10.     public void onCreate(Bundle savedInstanceState) {  
    11.         super.onCreate(savedInstanceState);  
    12.         setContentView(R.layout.main);  
    13.           
    14.         updateManager = new UpdateAppManager(this);  
    15.         updateManager.checkUpdateInfo();  
    16.     }  
    17.   
    18. }  
    UpdateAppManager.java
    1. package cn.lynn.autoupdate;  
    2.   
    3. import java.io.File;  
    4. import java.io.FileOutputStream;  
    5. import java.io.IOException;  
    6. import java.io.InputStream;  
    7. import java.net.HttpURLConnection;  
    8. import java.net.URL;  
    9.   
    10. import android.app.AlertDialog;  
    11. import android.app.Dialog;  
    12. import android.content.Context;  
    13. import android.content.DialogInterface;  
    14. import android.content.DialogInterface.OnClickListener;  
    15. import android.content.Intent;  
    16. import android.net.Uri;  
    17. import android.os.Environment;  
    18. import android.os.Handler;  
    19. import android.os.Message;  
    20. import android.view.LayoutInflater;  
    21. import android.view.View;  
    22. import android.widget.ProgressBar;  
    23.   
    24. public class UpdateAppManager {  
    25.     // 文件分隔符  
    26.     private static final String FILE_SEPARATOR = "/";  
    27.     // 外存sdcard存放路径  
    28.     private static final String FILE_PATH = Environment.getExternalStorageDirectory() + FILE_SEPARATOR +"autoupdate" + FILE_SEPARATOR;  
    29.     // 下载应用存放全路径  
    30.     private static final String FILE_NAME = FILE_PATH + "autoupdate.apk";  
    31.     // 更新应用版本标记  
    32.     private static final int UPDARE_TOKEN = 0x29;  
    33.     // 准备安装新版本应用标记  
    34.     private static final int INSTALL_TOKEN = 0x31;  
    35.       
    36.     private Context context;  
    37.     private String message = "检测到本程序有新版本发布,建议您更新!";  
    38.     // 以华为天天聊hotalk.apk为例  
    39.     private String spec = "http://222.42.1.209:81/1Q2W3E4R5T6Y7U8I9O0P1Z2X3C4V5B/mt.hotalk.com:8080/release/hotalk1.9.17.0088.apk";  
    40.     // 下载应用的对话框  
    41.     private Dialog dialog;  
    42.     // 下载应用的进度条  
    43.     private ProgressBar progressBar;  
    44.     // 进度条的当前刻度值  
    45.     private int curProgress;  
    46.     // 用户是否取消下载  
    47.     private boolean isCancel;  
    48.       
    49.     public UpdateAppManager(Context context) {  
    50.         this.context = context;  
    51.     }  
    52.       
    53.     private final Handler handler = new Handler(){  
    54.         @Override  
    55.         public void handleMessage(Message msg) {  
    56.             switch (msg.what) {  
    57.             case UPDARE_TOKEN:  
    58.                 progressBar.setProgress(curProgress);  
    59.                 break;  
    60.   
    61.             case INSTALL_TOKEN:  
    62.                 installApp();  
    63.                 break;  
    64.             }  
    65.         }  
    66.     };  
    67.       
    68.     /** 
    69.      * 检测应用更新信息 
    70.      */  
    71.     public void checkUpdateInfo() {  
    72.         showNoticeDialog();  
    73.     }  
    74.   
    75.     /** 
    76.      * 显示提示更新对话框 
    77.      */  
    78.     private void showNoticeDialog() {  
    79.         new AlertDialog.Builder(context)  
    80.             .setTitle("软件版本更新")  
    81.             .setMessage(message)  
    82.             .setPositiveButton("下载"new OnClickListener() {  
    83.                 @Override  
    84.                 public void onClick(DialogInterface dialog, int which) {  
    85.                     dialog.dismiss();  
    86.                     showDownloadDialog();  
    87.                 }  
    88.             }).setNegativeButton("以后再说"new OnClickListener() {  
    89.                 @Override  
    90.                 public void onClick(DialogInterface dialog, int which) {  
    91.                     dialog.dismiss();  
    92.                 }  
    93.             }).create().show();  
    94.     }  
    95.   
    96.     /** 
    97.      * 显示下载进度对话框 
    98.      */  
    99.     private void showDownloadDialog() {  
    100.         View view = LayoutInflater.from(context).inflate(R.layout.progressbar, null);  
    101.         progressBar = (ProgressBar) view.findViewById(R.id.progressBar);  
    102.         AlertDialog.Builder builder = new AlertDialog.Builder(context);  
    103.         builder.setTitle("软件版本更新");  
    104.         builder.setView(view);  
    105.         builder.setNegativeButton("取消"new OnClickListener() {  
    106.                 @Override  
    107.                 public void onClick(DialogInterface dialog, int which) {  
    108.                     dialog.dismiss();  
    109.                     isCancel = true;  
    110.                 }  
    111.             });  
    112.         dialog = builder.create();  
    113.         dialog.show();  
    114.         downloadApp();  
    115.     }  
    116.   
    117.     /** 
    118.      * 下载新版本应用 
    119.      */  
    120.     private void downloadApp() {  
    121.         new Thread(new Runnable() {  
    122.             @Override  
    123.             public void run() {  
    124.                 URL url = null;  
    125.                 InputStream in = null;  
    126.                 FileOutputStream out = null;  
    127.                 HttpURLConnection conn = null;  
    128.                 try {  
    129.                     url = new URL(spec);  
    130.                     conn = (HttpURLConnection) url.openConnection();  
    131.                     conn.connect();  
    132.                     long fileLength = conn.getContentLength();  
    133.                     in = conn.getInputStream();  
    134.                     File filePath = new File(FILE_PATH);  
    135.                     if(!filePath.exists()) {  
    136.                         filePath.mkdir();  
    137.                     }  
    138.                     out = new FileOutputStream(new File(FILE_NAME));  
    139.                     byte[] buffer = new byte[1024];  
    140.                     int len = 0;  
    141.                     long readedLength = 0l;  
    142.                     while((len = in.read(buffer)) != -1) {  
    143.                         // 用户点击“取消”按钮,下载中断  
    144.                         if(isCancel) {  
    145.                             break;  
    146.                         }  
    147.                         out.write(buffer, 0, len);  
    148.                         readedLength += len;  
    149.                         curProgress = (int) (((float) readedLength / fileLength) * 100);  
    150.                         handler.sendEmptyMessage(UPDARE_TOKEN);  
    151.                         if(readedLength >= fileLength) {  
    152.                             dialog.dismiss();  
    153.                             // 下载完毕,通知安装  
    154.                             handler.sendEmptyMessage(INSTALL_TOKEN);  
    155.                             break;  
    156.                         }  
    157.                     }  
    158.                     out.flush();  
    159.                 } catch (Exception e) {  
    160.                     e.printStackTrace();  
    161.                 } finally {  
    162.                     if(out != null) {  
    163.                         try {  
    164.                             out.close();  
    165.                         } catch (IOException e) {  
    166.                             e.printStackTrace();  
    167.                         }  
    168.                     }  
    169.                     if(in != null) {  
    170.                         try {  
    171.                             in.close();  
    172.                         } catch (IOException e) {  
    173.                             e.printStackTrace();  
    174.                         }  
    175.                     }  
    176.                     if(conn != null) {  
    177.                         conn.disconnect();  
    178.                     }  
    179.                 }  
    180.             }  
    181.         }).start();  
    182.     }  
    183.       
    184.     /** 
    185.      * 安装新版本应用 
    186.      */  
    187.     private void installApp() {  
    188.         File appFile = new File(FILE_NAME);  
    189.         if(!appFile.exists()) {  
    190.             return;  
    191.         }  
    192.         // 跳转到新版本应用安装页面  
    193.         Intent intent = new Intent(Intent.ACTION_VIEW);  
    194.         intent.setDataAndType(Uri.parse("file://" + appFile.toString()), "application/vnd.android.package-archive");  
    195.         context.startActivity(intent);  
    196.     }  
    197. }  
    三、案例效果展示
      
            新版本应用下载后,sdcard相关存放目录如下:
    路漫漫其修远兮 吾将上下而求索
  • 相关阅读:
    mybatis
    mybatis
    hadoop完全分布式搭建
    用构造器确保初始化
    HashMap的内部结构与hash冲突
    方法重载 与 方法覆盖
    Django后台管理admin或者adminx中使用富文本编辑器
    Celery在Django中的使用介绍
    django.db.utils.InternalError: (1060, "Duplicate column name 'user_id'")迁移报错解决方法
    Django2.0版本以上与pymsql 不匹配问题以及解决方法
  • 原文地址:https://www.cnblogs.com/hudabing/p/3213839.html
Copyright © 2020-2023  润新知