Android檢查更新下載安裝


檢查更新是任何app都會用到功能,任何一個app都不可能第一個版本就能把所有的需求都能實現,通過不斷的挖掘需求迭代才能使app變的越來越好。檢查更新自動下載安裝分以下幾個步驟:

  • 請求服務器判斷是否有最新版本(通過versionCode)
  • 如果有最新版本,就把最新的apk文件下載到本地
  • 下載完成之后給系統發起一個安裝的Intent。

打開項目下面app下面build.gradle文件,我們可以看到里面有兩個屬性versionCode跟versionName,versionCode是一個int類型的值,用他來更新版本,versionName是一個浮點型的值,給用戶看的,告訴用戶當前的是幾點幾版本。每次app升級的時候,都要對這兩個值進行增加。這里我們就用默認的值好了。

startup_process

因為檢查更新需要請求服務器,所以我們引入之前封裝的okhttp庫:

compile 'com.ansen.http:okhttpencapsulation:1.0.1'

需要訪問網絡跟寫入sdcard的權限,記得在AndroidManifest.xml鍾增加權限。

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

需要重寫Application,並且在AndroidManifest.xml文件中給application標簽name屬性指向重寫的MyApplication,在MyApplication中初始化HTTPCaller。

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();

        HttpConfig httpConfig = new HttpConfig();
        httpConfig.setAgent(true);//有代理的情況能不能訪問
        httpConfig.setDebug(true);//是否debug模式 如果是debug模式打印log
        httpConfig.setTagName("ansen");//打印log的tagname

        //可以添加一些公共字段 每個接口都會帶上
        httpConfig.addCommonField("pf", "android");
        httpConfig.addCommonField("version_code", "" + Utils.getVersionCode(getApplicationContext()));

        //初始化HTTPCaller類
        HTTPCaller.getInstance().setHttpConfig(httpConfig);
    }
}

我們把version_code作為公共參數,通過Utils類的getVersionCode方法獲取值。getVersionCode方法需要傳入一個context對象,通過Context獲取包管理器,調用PackageManager的getPackageInfo方法獲取包信息,調用他的公有屬性versionCode獲取當前版本號。

public static int getVersionCode(Context ctx) {
    // 獲取packagemanager的實例
    int version = 0;
    try {
        PackageManager packageManager = ctx.getPackageManager();
        //getPackageName()是你當前程序的包名
        PackageInfo packInfo = packageManager.getPackageInfo(ctx.getPackageName(), 0);
        version = packInfo.versionCode;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return version;
}

MainActivity對應的activity_main.xml文件比較簡單,上面一個TextView用來顯示當前版本號,下面一個檢查更新按鈕。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp">

    <TextView
        android:id="@+id/tv_current_version_code"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:textSize="16sp"
        android:text="當前版本"/>

    <Button
        android:id="@+id/btn_check_update"
        android:layout_marginTop="10dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="檢查更新"/>
</LinearLayout>

MainActivity.java(為了方便講解先看一部分代碼),在onCreate中給顯示當前版本的TextView賦值,跟檢查更新的按鈕設置點擊監聽。點擊按鈕發送一個get請求服務器。我們知道有沒有新版本是通過versionCode的值來判斷的,但是我們這里卻沒有在請求url后面加參數,因為我們在MyApplication中已經把versionCode設置成了公共參數。

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private ProgressDialog progressDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView tvCurrentVersionCode= (TextView) findViewById(R.id.tv_current_version_code);
        tvCurrentVersionCode.setText("當前版本:"+ Utils.getVersionCode(this));

        findViewById(R.id.btn_check_update).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_check_update://檢查更新
                HTTPCaller.getInstance().get(CheckUpdate.class,"http://139.196.35.30:8080/OkHttpTest/checkUpdate.do",null,requestDataCallback);
                break;
        }
    }
   
   ·············
}

get請求回調監聽,先判斷返回的狀態碼,如果狀態碼等於0就是有新版本,有新版本的話下載url也是有值的,把下載url傳給showUpdaloadDialog方法。

private RequestDataCallback<CheckUpdate> requestDataCallback=new RequestDataCallback<CheckUpdate>(){
        @Override
        public void dataCallback(CheckUpdate obj) {
            if(obj!=null){
                if(obj.getErrorCode()==0){//有新版本
                    showUpdaloadDialog(obj.getUrl());
                }else{//沒有新版本
                    Toast.makeText(MainActivity.this,obj.getErrorReason(),Toast.LENGTH_LONG).show();
                }
            }
        }
};

顯示是否更新對話框,彈一個對話框讓用戶去判斷要不要更新,總是友好一點。我看國內一些很大公司的app如果用戶的手機有wifi的話都是直接后台下載更新包,而不經過用戶的同意,我覺得這種做法太不考慮用戶的感受了。Android系統的開放性總是用來干一些影響用戶體驗的事情。這里我們談一個確認更新對話框。如果用戶點擊了確認按鈕就調用startUpload方法。當前點擊取消按鈕關閉對話框啥都不干了。

private void showUpdaloadDialog(final String downloadUrl){
    // 這里的屬性可以一直設置,因為每次設置后返回的是一個builder對象
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    // 設置提示框的標題
    builder.setTitle("版本升級").
            setIcon(R.mipmap.ic_launcher). // 設置提示框的圖標
            setMessage("發現新版本!請及時更新").// 設置要顯示的信息
            setPositiveButton("確定", new DialogInterface.OnClickListener() {// 設置確定按鈕
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    startUpload(downloadUrl);//下載最新的版本程序
                }
            }).setNegativeButton("取消", null);//設置取消按鈕,null是什么都不做,並關閉對話框
    AlertDialog alertDialog = builder.create();
    // 顯示對話框
    alertDialog.show();
}

開始更新方法,首先創建一個進度條對話框,設置進度條樣式,設置messgage,然后調用Utils類的getSaveFilePath靜態方法獲取一個sdcard的路徑,把下載下來的apk文件就保存在這個路徑。然后調用HTTPCaller類的downloadFile方法去下載文件。有三個參數:下載url,文件保存路徑,下載進度回調。下載進度回調是一個ProgressUIListener接口,用內部內的方式重寫三個方法。onUIProgressStart下載開始時把總文件長度賦值給進度條的總長度,顯示進度條。onUIProgressChanged下載進度變化時更新進度條。onUIProgressFinish下載完成銷毀進度條,調用openAPK方法。

private void startUpload(String downloadUrl){
    progressDialog=new ProgressDialog(this);
    progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    progressDialog.setMessage("正在下載新版本");
    progressDialog.setCancelable(false);//不能手動取消下載進度對話框

    final String fileSavePath=Utils.getSaveFilePath(downloadUrl);
    HTTPCaller.getInstance().downloadFile(downloadUrl,fileSavePath,null,new ProgressUIListener(){

        @Override
        public void onUIProgressStart(long totalBytes) {//下載開始
            progressDialog.setMax((int)totalBytes);
            progressDialog.show();
        }

        //更新進度
        @Override
        public void onUIProgressChanged(long numBytes, long totalBytes, float percent, float speed) {
            progressDialog.setProgress((int)numBytes);
        }

        @Override
        public void onUIProgressFinish() {//下載完成
            Toast.makeText(MainActivity.this,"下載完成",Toast.LENGTH_LONG).show();
            progressDialog.dismiss();
            openAPK(fileSavePath);
        }
    });
}

下載完成安裝apk,給系統發送一個intent。

private void openAPK(String fileSavePath){
    Intent intent = new Intent();
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.setAction(Intent.ACTION_VIEW);
    intent.setDataAndType(Uri.parse("file://"+fileSavePath),"application/vnd.android.package-archive");
    startActivity(intent);
}

運行源碼,效果圖如下:
這里寫圖片描述

注意事項:

這里我們為什么有新版本?

我們看第一張效果圖當前的版本是1,我早就打包了一個versionCode等於2的簽名apk放到服務器上了,所以只要我們給的參數versionCode的值小於2都是可以升級的。

覆蓋安裝簽名問題

我們都知道在調試的時候直接運行app裝到手機上安裝包是臨時簽名,所以再企業開發中每次打這個版本的最后包的時候都會正式簽名一下,保證所有版本的安裝包都是一個簽名,只有簽名一樣才能覆蓋安裝。所以你們拿到源碼的時候直接運行app,點擊更新,下載完成,點擊安裝的時候會出現應用未安裝的情況。在項目的根目錄下我有新建一個jks文件夾,里面包含了簽名文件,還有一個已經簽好名的1.0版本,如果你想先看效果可以把1.0版本的apk文件通過社交軟件什么的發送到手機上,安裝升級能覆蓋安裝的。當然你也可以自己簽名。簽名文件跟密碼都在jks文件夾下。

源碼下載

如果你想第一時間看我的后期文章,掃碼關注公眾號,每周不定期推送Android開發實戰教程文章...

      Android開發666 - 安卓開發技術分享
             掃描二維碼加關注

Android開發666


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM