安卓okhttpUtils下載文件(安裝包)並打開(安裝)實例

okhttpUtils是okhttp的一個工具包,首先在app的build.gradle中添加以下內容:

    implementation 'com.squareup.okhttp3:okhttp:4.3.0'
    implementation 'com.squareup.okio:okio:2.4.3'
    implementation 'com.zhy:okhttputils:2.6.2'

	//實例中使用了Toast和Dialog的第三方框架,如需使用請添加以下內容
	implementation 'com.github.GrenderG:Toasty:1.3.0'
    implementation 'com.afollestad.material-dialogs:core:0.9.6.0'

首先實例流程爲:①獲取當前APP版本號 ②請求檢查更新接口 ③若有新版本則提示下載 ④若點擊下載則通過異步請求將服務器上的APK文件下載完成後自動跳轉安裝界面

注意由於谷歌要求針對高版本安卓開發,低版本不允許上架, 所以當前實例並未考慮低版本安卓,測試機爲安卓7-10

首先在安卓7以上存在一個問題,就是普通file格式的uri無法直接使用,需通過共享目錄生成content格式的uri,所以我們需要在androidmanifest.xml的application中添加以下內容:

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.packagename.fileProvider" //改爲你的包名.fileProvider即可
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

然後在res目錄中新建一個xml目錄,如果已有則不需要新建,在xml中新建一個files_paths.xml並寫入以下內容:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <!-- 物理路徑爲Context.getFilesDir() + /files/... -->
    <files-path path="files" name="files" />
    <!-- 物理路徑爲Context.getCacheDir() + /files/... -->
    <cache-path path="files" name="cache" />
    <!-- 物理路徑爲Environment.getExternalStorageDirectory() + /files/... -->
    <external-path path="files" name="external" />
    <!-- 物理路徑爲Context.getExternalFilesDir(String) + /files/... -->
    <external-files-path path="files" name="externalfiles"/>
    <!-- 物理路徑爲Context.getExternalCacheDir() + /files/... -->
    <external-cache-path  path="files" name="externalcache"/>
    <!-- 物理路徑爲`Context.getExternalMediaDirs() + /files/..., 要求API21+ -->
    <external-media-path name="externalmedia" path="files" />
    <root-path name="root_path" path="."/>
</paths>

這樣我們的共享目錄就配置好了,在代碼中直接使用即可,接下來我將直接貼出檢查更新的完整點擊事件供大家參考(重要部分在代碼中註釋標出):

check_view.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        long versionCode = 1000;
        //獲取當前APP的版本號
        try {
            PackageInfo packageInfo = getContext().getApplicationContext()
                    .getPackageManager()
                    .getPackageInfo(getContext().getPackageName(), 0);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                versionCode = packageInfo.getLongVersionCode();
            } else {
                versionCode = packageInfo.versionCode;
            }
        } catch (PackageManager.NameNotFoundException e) {
            Log.e("", e.getMessage());
        }

		//請求地址+等待提示框
        String host = new Defines().SERVER_HOST+"checkUpdate";
        final MaterialDialog waitForDialog = new MaterialDialog.Builder(getActivity())
                .content("請稍等...")
                .progress(true,-1)//等待圖標 true=圓形icon false=進度條
                .cancelable(false)//不會被取消 (包括返回鍵和外部點擊都無法取消)
                .build();
        waitForDialog.show();

		//調用檢查更新接口,傳入當前版本號
        OkHttpUtils
                .post()
                .url(host)
                .addParams("version_code",""+versionCode)
                .build()
                .execute(new StringCallback() {
                    @Override
                    public void onError(Call call, Exception e, int id) {
                        waitForDialog.dismiss();
                        Toasty.error(getActivity(),"服務器請求失敗", Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onResponse(String response, int id) {
                        waitForDialog.dismiss();
                        try {
                            JSONObject jsonObject = new JSONObject(response);
                            int code = jsonObject.getInt("code");
                            //code=200爲最新版本無需更新   code=250爲有新版本可供下載
                            if (code==200) {
                                Toasty.success(getActivity(),jsonObject.getString("msg"),Toast.LENGTH_SHORT).show();
                            } else if(code==250) {
                                final JSONObject data = jsonObject.getJSONObject("data");
                                //將後臺編寫的更新日誌的<br>打散重組爲\n以在安卓可以換行提示
                                String log = "";
                                String[] chrstr = data.getString("update_log").split("<br>");
                                for(int i=0;i<chrstr.length;i++)
                                    log = log + chrstr[i]+"\n";

                                MaterialDialog dialog = new MaterialDialog.Builder(getContext())
                                        .title(jsonObject.getString("msg"))
                                        .content(log)
                                        .positiveText("下載更新")
                                        .negativeText("以後再說")
                                        .cancelable(true)
                                        .onPositive(new MaterialDialog.SingleButtonCallback() { 
                                            @Override
                                            public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
												//獲取APP內部存儲的chche文件夾路徑
                                                if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !Environment.isExternalStorageRemovable()) {
                                                    cachePath = getActivity().getExternalCacheDir().getPath();
                                                } else {
                                                    cachePath = getActivity().getFilesDir().getAbsolutePath();
                                                }
												//新建一個下載進度條並允許點擊其他區域關閉
                                                final ProgressDialog progressDialog = new ProgressDialog(getContext());
                                                progressDialog.setTitle("正在下載,請耐心等待...");
                                                progressDialog.setMessage("點擊其他區域或返回以轉入後臺下載");
                                                progressDialog.setCancelable(true);
                                                progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                                                progressDialog.show();

                                                try {
                                                    //通過okhttpUtils下載文件
                                                    OkHttpUtils.get()
                                                            .url(data.getString("position"))
                                                            .build()
                                                            .execute(new FileCallBack(cachePath,"fingerdorm.apk") {
                                                                @Override
                                                                public void onError(Call call, Exception e, int id) {
                                                                    Toasty.error(getActivity(),"下載失敗",Toast.LENGTH_SHORT).show();
                                                                }
																//inpogress回調爲更新進度條
                                                                @Override
                                                                public void inProgress(float progress, long total, int id) {
                                                                    super.inProgress(progress, total, id);
                                                                    progressDialog.setProgress((int) (100 * progress));
                                                                }
																//下載完成,處理打開安裝
                                                                @Override
                                                                public void onResponse(File downloadFile, int id) {
                                                                    Toasty.success(getActivity(),"下載完成,即將啓動安裝",Toast.LENGTH_LONG).show();
                                                                    progressDialog.hide();
                                                                    progressDialog.dismiss();
                                                                    //開啓子線程,延遲三秒後執行安裝
                                                                    new Thread(new Runnable()
                                                                    {
                                                                        @Override
                                                                        public void run()
                                                                        {
                                                                            try {
                                                                                sleep(3000);

                                                                                if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !Environment.isExternalStorageRemovable()) {
                                                                                    cachePath = getContext().getExternalCacheDir().getPath();
                                                                                } else {
                                                                                    cachePath = getContext().getFilesDir().getAbsolutePath();
                                                                                }
                                                                                File uriFile = new File(cachePath +"/fingerdorm.apk");												
                                                                                //這裏獲取uri的第二個參數一定要和androidmanifest中配置的的對應
                                                                                Uri uri = getUriForFile(getContext(), "com.packaname.fileProvider", uriFile);
                                                                                Intent intent = new Intent(Intent.ACTION_VIEW);
                                                                                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                                                                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                                                                                //打開APK執行的TYPE爲"application/vnd.android.package-archive"
                                                                                intent.setDataAndType(uri,"application/vnd.android.package-archive");
                                                                                getContext().startActivity(intent);
                                                                            } catch (Exception e) {
                                                                                Looper.prepare();
                                                                                Toasty.error(getActivity(), "自動安裝失敗,請手動安裝", Toast.LENGTH_SHORT).show();
                                                                                Looper.loop();
                                                                            }
                                                                        }
                                                                    }).start();
                                                                }
                                                            });
                                                } catch (JSONException e) {
                                                    Toasty.error(getActivity(), "服務器數據解析失敗", Toast.LENGTH_SHORT).show();
                                                }
                                            }
                                        })
                                        .onNegative(new MaterialDialog.SingleButtonCallback() { 
                                        
                                            @Override
                                            public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                                            }
                                        })
                                        .build();
                                dialog.show();
                            }else{
                                Toasty.error(getActivity(),jsonObject.getString("msg"), Toast.LENGTH_SHORT).show();
                            }
                        } catch (JSONException e) {
                            e.printStackTrace();
                            Toasty.warning(getActivity(),"檢查更新失敗",Toast.LENGTH_LONG).show();
                        }
                    }
                });
    }
});
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章