Android7.0自動更新適配 包解析異常
在Android7.0的手機上,自動更新的時候出現(xiàn)包解析異常,在其他的手機上沒有這個問題。
原因:
Android7.0引入私有目錄被限制訪問和StrictMode API 。私有目錄被限制訪問是指在Android7.0中為了提高應用的安全性,在7.0上應用私有目錄將被限制訪問。StrictMode API是指禁止向你的應用外公開 file:// URI。 如果一項包含文件 file:// URI類型 的 Intent 離開你的應用,則會報出異常。
解決辦法:
第一步:在AndroidManifest.xml中注冊provider,provider可以向應用外提供數(shù)據(jù)。
<provider android:authorities="包名.fileprovider" android:name="android.support.v4.content.FileProvider" android:grantUriPermissions="true"http://這是設置uri的權(quán)限 android:exported="false"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/>//在第二步的時候會有介紹 </provider>
第二步:在res/xml中創(chuàng)建file_paths.xml文件。
<?xml version="1.0" encoding="utf-8"?> <resources> <paths> <external-path path="" name="download" /> </paths> </resources>
第三步:貼出我的自動更新下載的代碼
public class UpdateManager { private Context mContext; private static String savePath ; private String saveFileName ; private ProgressBar mProgress; //下載進度條控件 private static final int DOWNLOADING = 1; //表示正在下載 private static final int DOWNLOADED = 2; //下載完畢 private static final int DOWNLOAD_FAILED = 3; //下載失敗 private int progress; //下載進度 private boolean cancelFlag = false; //取消下載標志位 private String serverVersion; //從服務器獲取的版本號 private String apkUrl; // private String apkUrl = "http://liuliu.lejuhuyu.com/AndroidApk/liuliu-dashou-app-1.0.2.apk"; private String clientVersion; //客戶端當前的版本號 private String updateDescription = "請更新當前最新版本"; //更新內(nèi)容描述信息 private String forceUpdate; //是否強制更新 private String update; private VersionBean mVersionBean; private AlertDialog alertDialog1, alertDialog2; //表示提示對話框、進度條對話框 public UpdateManager(Context context,VersionBean versionBean) { this.mContext = context; this.mVersionBean = versionBean; apkUrl = "http://liuliu.lejuhuyu.com/AndroidApk/liuliu-dashou-app-"+versionBean.getLastVersion()+".apk"; savePath = Environment.DIRECTORY_DOWNLOADS; saveFileName = savePath + "/liuliu-dashou-app-"+versionBean.getLastVersion()+".apk"; } /** 顯示更新對話框 */ public void showNoticeDialog() { serverVersion = mVersionBean.getLastVersion(); clientVersion = mVersionBean.getVersion(); L.e("apkUrl="+apkUrl); L.e("savePath="+savePath); L.e("saveFileName="+saveFileName); // forceUpdate = StringUtils.getVersion(); // forceUpdate = "1"; forceUpdate = mVersionBean.getImportant(); update = mVersionBean.getUpdate(); //如果版本最新,則不需要更新 if (serverVersion.equals(clientVersion)) return; if (update.equals("2")) return; AlertDialog.Builder dialog = new AlertDialog.Builder(mContext); dialog.setTitle("發(fā)現(xiàn)新版本 :" + serverVersion); dialog.setMessage(updateDescription); dialog.setPositiveButton("現(xiàn)在更新", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { // TODO Auto-generated method stub arg0.dismiss(); showDownloadDialog(); } }); //是否強制更新 if (forceUpdate.equals("2")) { dialog.setNegativeButton("待會更新", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { // TODO Auto-generated method stub arg0.dismiss(); } }); } alertDialog1 = dialog.create(); alertDialog1.setCancelable(false); alertDialog1.show(); } /** 顯示進度條對話框 */ public void showDownloadDialog() { AlertDialog.Builder dialog = new AlertDialog.Builder(mContext); dialog.setTitle("正在更新"); final LayoutInflater inflater = LayoutInflater.from(mContext); View v = inflater.inflate(R.layout.softupdate_progress, null); mProgress = (ProgressBar) v.findViewById(R.id.update_progress); dialog.setView(v); //如果是強制更新,則不顯示取消按鈕 // if (forceUpdate.equals("1")) { // dialog.setNegativeButton("取消", new DialogInterface.OnClickListener() { // @Override // public void onClick(DialogInterface arg0, int arg1) { // // TODO Auto-generated method stub // arg0.dismiss(); // cancelFlag = false; // } // }); // } alertDialog2 = dialog.create(); alertDialog2.setCancelable(false); alertDialog2.show(); //下載apk downloadAPK(); } DownloadManager manager; Cursor cursor; DownloadManager.Request down; DownloadManager.Query query; ContentObserver contentObserver; /** 下載apk的線程 */ public void downloadAPK() { manager = (DownloadManager) LiuLiuApplication.getContext().getSystemService(Context.DOWNLOAD_SERVICE); down = new DownloadManager.Request(Uri.parse(apkUrl)); // 設置允許使用的網(wǎng)絡類型,這里是移動網(wǎng)絡和wifi都可以 down.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI); // 顯示下載界面 down.setVisibleInDownloadsUi(true); // 設置下載路徑和文件名 down.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "liuliu-dashou-app-"+mVersionBean.getLastVersion() + ".apk"); down.setMimeType("application/vnd.android.package-archive"); // 設置為可被媒體掃描器找到 down.allowScanningByMediaScanner(); down.setAllowedOverRoaming(false); // down.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); long id = manager.enqueue(down); query = new DownloadManager.Query().setFilterById(id); contentObserver = new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange) { // super.onChange(selfChange); boolean downloading = true; while(downloading){ cursor = manager.query(query); try { if (cursor != null && cursor.moveToFirst()) { int bytes_downloaded = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)); int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)); progress = (int) ((bytes_downloaded * 100) / bytes_total); mHandler.sendEmptyMessage(DOWNLOADING); if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))==DownloadManager.STATUS_SUCCESSFUL) { mHandler.sendEmptyMessage(DOWNLOADED); }else if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))==DownloadManager.STATUS_FAILED){ mHandler.sendEmptyMessage(DOWNLOAD_FAILED); } } }catch (Exception e){ e.printStackTrace(); mHandler.sendEmptyMessage(DOWNLOAD_FAILED); }finally { if (cursor != null){ downloading = false; cursor.close(); } } } } }; mContext.getContentResolver().registerContentObserver(Uri.parse("content://downloads/"),true,contentObserver); } /** 更新UI的handler */ private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub switch (msg.what) { case DOWNLOADING: mProgress.setProgress(progress); break; case DOWNLOADED: if (alertDialog2 != null) alertDialog2.dismiss(); installAPK(); break; case DOWNLOAD_FAILED: ToastUtil.getInstance(mContext,"網(wǎng)絡斷開,請稍候再試",false).show(); break; default: break; } } }; /** 下載完成后自動安裝apk */ public void installAPK() { File apkFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),"liuliu-dashou-app-"+mVersionBean.getLastVersion() + ".apk"); if (!apkFile.exists()) { return; } if (Build.VERSION.SDK_INT>=24){ Uri apkUri = FileProvider.getUriForFile(mContext, LiuLiuApplication.getContext().getPackageName()+".fileprovider", apkFile); Intent install = new Intent(Intent.ACTION_VIEW); install.addCategory(Intent.CATEGORY_DEFAULT); install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); install.setDataAndType(apkUri, "application/vnd.android.package-archive"); mContext.startActivity(install); } else { Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.addCategory(Intent.CATEGORY_DEFAULT); intent.setType("application/vnd.android.package-archive"); intent.setData(Uri.fromFile(apkFile)); intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivity(intent); } } }
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
- Android跨進程拋異常的原理的實現(xiàn)
- Android編程實現(xiàn)項目中異常捕獲及對應Log日志文件保存功能
- Android Studio升級到3.0 Terminal 中文顯示異常解決
- Android 全局異常捕獲實例詳解
- android 捕捉異常并上傳至服務器的簡單實現(xiàn)
- Android Studio下載更新Android SDK網(wǎng)絡異?;驘o法下載
- Android 中Crash時如何獲取異常信息詳解及實例
- Android異常 java.lang.IllegalStateException解決方法
- AndroidStudio利用android-support-multidex解決64k的各種異常
- 安卓中出現(xiàn)過的一些容易被忽略的異常整理
相關(guān)文章
Android使用Activity實現(xiàn)簡單的可輸入對話框
大家在做彈出對話框效果的時候最容易想到的是用Dialog顯示,但其實彈出對話框的實現(xiàn)效果有兩種:Dialog和Activity,那么下面這篇文章就來給大家介紹了關(guān)于Android使用Activity如何實現(xiàn)一個簡單的可輸入對話框的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。2017-10-10Android自定義view實現(xiàn)圓形、圓角和橢圓圖片(BitmapShader圖形渲染)
這篇文章運用實例代碼介紹如何在Android中自定義view,使用BitmapShader圖形渲染方法來實現(xiàn)圓形、圓角和橢圓的繪制,有需要的可以參考借鑒。2016-08-08flutter實現(xiàn)更新彈窗內(nèi)容例子(親測有效)
Flutter是一款移動應用程序SDK,包含框架、widget和工具,這篇文章給大家介紹flutter實現(xiàn)更新彈窗內(nèi)容例子,親測可以使用,需要的朋友參考下吧2021-04-04Android SharedPreference存儲文件三步走
SharedPreferences是安卓平臺上一個輕量級的存儲類,用來保存應用的一些常用配置,比如Activity狀態(tài),Activity暫停時,將此activity的狀態(tài)保存到SharedPereferences中;當Activity重載,系統(tǒng)回調(diào)方法onSaveInstanceState時,再從SharedPreferences中將值取出2023-01-01Android NotificationManager簡單使用詳解
這篇文章主要為大家詳細介紹了Android NotificationManager的簡單使用,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11Android布局技巧之創(chuàng)建可重用的UI組件
這篇文章主要為大家詳細介紹了Android布局技巧之創(chuàng)建可重用的UI組件,文中提到了include標簽的使用方法,感興趣的小伙伴們可以參考一下2016-05-05