Linux編程
點擊右側關注,免費入門到精通!
作者丨bear~
http://www.apkbus.com/blog-302849-78954.html
問題描述
內容目錄
Toggle現象
代碼執行安裝Apk,出現系統彈框解析錯誤,解析包時出現錯誤
場景
在華為P20 Android 8.0 手機上,下載Apk並使用通知欄進度條顯示,開啟應用鎖屏通知權限,下載過程在鎖屏情況下進行,下載完成後自動執行安裝Apk,在解鎖後出現系統彈框,解析包出現錯誤。
解決之前安裝Apk的方法
首先在AndroidManifest中聲明fileProvider
<providerandroid:name="android.support.v4.content.FileProvider"android:authorities="${applicationId}.fileprovider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/file_path"/></provider>
provider屬性說明
res包下創建file_path.xml
<?xmlversion="1.0"encoding="utf-8"?><pathsxmlns:android="http://schemas.android.com/apk/res/android"><external-pathname="external_path"path="test"/><cache-pathname="internal_path"path="test"/>這里可以創建很多個paths,但是每個paths的name不能一樣</paths>
path 說明
<files-pathname="*name*"path="*path*"/>對應的是:Context.getFileDir()的路徑地址對應路徑:Context.getFileDir()+"/${path}/"得到路徑:content://${applicationId}/&{name}/<cache-pathname="*name*"path="*path*"/>對應路徑:Context.getCacheFir()+"/${path}/"得到路徑:content://${applicationId}/&{name}/<external-pathname="*name*"path="*path*"/>對應路徑:Environment.getExternalStorageDirectory()+"/${path}/"得到路徑:content://${applicationId}/&{name}/<external-files-pathname="*name*"path="*path*"/>對應路徑:Context.getExternalStorageDirectory()+"/${path}/"得到路徑:content://${applicationId}/&{name}/<external-cache-pathname="*name*"path="*path*"/>對應路徑:Context.getExternalCacheDir()+"/${path}/"得到路徑:content://${applicationId}/&{name}/
舉個例子說明:
path做如下聲明<pathsxmlns:android="http://schemas.android.com/apk/res/android"><files-pathname="my_images"path="images/"/></paths>FileimagePath=newFile(Context.getFilesDir(),"images");FilenewFile=newFile(imagePath,"default_image.jpg");UricontentUri=getUriForFile(getContext(),"com.mydomain.fileprovider",newFile);contentUri值為:content://com.mydomain.fileprovider/my_images/default_image.jpg
安裝apk的方法(7.0版本兼容問題)
publicstaticvoidinstallApk(Contextcontext,FileapkFile){try{Intentintent=newIntent(Intent.ACTION_VIEW);UriapkUri=null;//判斷版本是否是7.0及7.0以上if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){apkUri=FileProvider.getUriForFile(context,BuildConfig.APPLICATION_ID+".fileProvider",apkFile);//添加對目標應用臨時授權該Uri所代表的文件intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);}else{apkUri=Uri.fromFile(apkFile);}intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);intent.setDataAndType(apkUri,"application/vnd.android.package-archive");context.startActivity(intent);}catch(Exceptione){e.printStackTrace();}}
Android 8.0系統需要聲明權限
<uses-permissionandroid:name="android.permission.REQUEST_INSTALL_PACKAGE"/>
OK,以上就是大家普遍解決7.0,以及8.0版本兼容問題的方法。
但是,在上文描述的場景中依然報出了錯誤:
java.lang.SecurityException:PermissionDenial:openingproviderandroid.support.v4.content.FileProviderfromProcessRecord{cc3ad2316425:com.android.packageinstaller/u0a21}(pid=16425,uid=10021)thatisnotexportedfromuid10340
問題定位
經過短暫的懵逼後,開始通過各種方式,探索問題的原因。
根據系統log分析,猜測在鎖屏時,用於安裝Apk的service處於休眠或者不可用的狀態,導致通過intent.addflags方式賦予的臨時權限失效了。於是,再次仔細看了官方文檔後,發現還有一個方法,可以生成權限且在主動調用方法或者手機重啟後才會失效。
改進後的代碼
publicstaticvoidinstallApk(Contextcontext,FileapkFile){try{Intentintent=newIntent(Intent.ACTION_VIEW);UriapkUri=null;//判斷版本是否是7.0及7.0以上if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){apkUri=FileProvider.getUriForFile(context,BuildConfig.APPLICATION_ID+".fileProvider",apkFile);//添加對目標應用臨時授權該Uri所代表的文件intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);}else{apkUri=Uri.fromFile(apkFile);}intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);intent.setDataAndType(apkUri,"application/vnd.android.package-archive");//查詢所有符合intent跳轉目標應用類型的應用,注意此方法必須放置setDataAndType的方法之後List<ResolveInfo>resInfoList=context.getPackageManager().queryIntentActivities(intent,PackageManager.MATCH_DEFAULT_ONLY);//然後全部授權for(ResolveInforesolveInfo:resInfoList){StringpackageName=resolveInfo.activityInfo.packageName;context.grantUriPermission(packageName,uri,Intent.FLAG_GRANT_WRITE_URI_PERMISSION|Intent.FLAG_GRANT_READ_URI_PERMISSION);}context.startActivity(intent);}catch(Exceptione){e.printStackTrace();}}
再次嘗試,此問題再沒有出現。
推薦↓↓↓
長
按
關
註
?【16個技術公眾號】都在這里!
涵蓋:工程師大咖、源碼共讀、工程師共讀、數據結構與算法、黑客技術和網路安全、大數據科技、編程前端、Java、Python、Web編程開發、Android、iOS開發、Linux、數據庫研發、幽默工程師等。





專注在 兩性、愛情等領域