Android 9.0自动更新 安装包解析错误 java.lang.SecurityException: Permission Denial
Posted 吹着空调哼着歌
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 9.0自动更新 安装包解析错误 java.lang.SecurityException: Permission Denial相关的知识,希望对你有一定的参考价值。
在android 9.0自动下载更新时 遇到 安装包解析错误
在android 7.0使用的是同一套框架却没有问题?
然后通过adb命令抓取一下异常发现
12-18 19:21:32.665 4804 5604 W InstallStaging: java.lang.SecurityException: Permission Denial: reading android.support.v4.content.FileProvider uri content://com.***.***.update_app.file_provider/download/update/***.apk from pid=4804, uid=1000 requires the provider be exported, or grantUriPermission()
12-18 19:21:32.665 4804 5604 W InstallStaging: at android.os.Parcel.createException(Parcel.java:1950)
12-18 19:21:32.665 4804 5604 W InstallStaging: at android.os.Parcel.readException(Parcel.java:1918)
12-18 19:21:32.665 4804 5604 W InstallStaging: at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:183)
12-18 19:21:32.665 4804 5604 W InstallStaging: at android.database.DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(DatabaseUtils.java:146)
12-18 19:21:32.665 4804 5604 W InstallStaging: at android.content.ContentProviderProxy.openTypedAssetFile(ContentProviderNative.java:698)
12-18 19:21:32.665 4804 5604 W InstallStaging: at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1459)
12-18 19:21:32.665 4804 5604 W InstallStaging: at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1296)
12-18 19:21:32.665 4804 5604 W InstallStaging: at android.content.ContentResolver.openInputStream(ContentResolver.java:1016)
12-18 19:21:32.665 4804 5604 W InstallStaging: at com.android.packageinstaller.InstallStaging$StagingAsyncTask.doInBackground(InstallStaging.java:167)
12-18 19:21:32.665 4804 5604 W InstallStaging: at com.android.packageinstaller.InstallStaging$StagingAsyncTask.doInBackground(InstallStaging.java:160)
12-18 19:21:32.665 4804 5604 W InstallStaging: at android.os.AsyncTask$2.call(AsyncTask.java:333)
12-18 19:21:32.665 4804 5604 W InstallStaging: at java.util.concurrent.FutureTask.run(FutureTask.java:266)
12-18 19:21:32.665 4804 5604 W InstallStaging: at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
12-18 19:21:32.665 4804 5604 W InstallStaging: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
12-18 19:21:32.665 4804 5604 W InstallStaging: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
12-18 19:21:32.665 4804 5604 W InstallStaging: at java.lang.Thread.run(Thread.java:764)
发现Android9.0是需要权限读取fileProvider和uri的
于是我看了一下三方框架的源码,确实没有加权限
private Intent installIntent(Context context, String path)
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addCategory(Intent.CATEGORY_DEFAULT);
String fileProviderAuthority = getFileProviderAuthority(context);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && null!= fileProviderAuthority)
Uri fileUri = FileProvider.getUriForFile(context, fileProviderAuthority, new File(path));
intent.setDataAndType(fileUri, "application/vnd.android.package-archive");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
else
intent.setDataAndType(Uri.fromFile(new File(path)), "application/vnd.android.package-archive");
return intent;
于是我就扒了一下源码对其进行修改
private Intent installIntent(Context context, String path)
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addCategory(Intent.CATEGORY_DEFAULT);
String fileProviderAuthority = getFileProviderAuthority(context);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && null!= fileProviderAuthority)
Uri fileUri = FileProvider.getUriForFile(context, fileProviderAuthority, new File(path));
intent.setDataAndType(fileUri, "application/vnd.android.package-archive");
grantUriPermission(getPackageName(), fileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
else
intent.setDataAndType(Uri.fromFile(new File(path)), "application/vnd.android.package-archive");
return intent;
测试通过,完美安装,没有出现解析失败问题
代码:
<!--AndroidManifest.xml-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET"/>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="包名.file_provider"
android:exported="false"
android:grantUriPermissions="true">
<!-- 元数据 -->
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"
tools:replace="android:resource" />
</provider>
<service android:name=".UpdateService"/>//从源码下载的升级下载安装apk的服务
<!-- file_paths.xml -->
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path path="." name="download" />
<external-cache-path
name="storage/emulated/0"
path="." />
</paths>
/**
* Created by Sun on 2020/12/19.
*/
public class UpdateService extends Service
public static final String TAG = "UpdateService";
public static final String ACTION = "me.shenfan.UPDATE_APP";
public static final String STATUS = "status";
public static final String PROGRESS = "progress";
public static boolean DEBUG = false;
//下载大小通知频率
public static final int UPDATE_NUMBER_SIZE = 1;
public static final int DEFAULT_RES_ID = -1;
public static final int UPDATE_PROGRESS_STATUS = 0;
public static final int UPDATE_ERROR_STATUS = -1;
public static final int UPDATE_SUCCESS_STATUS = 1;
//params
private static final String URL = "downloadUrl";
private static final String ICO_RES_ID = "icoResId";
private static final String ICO_SMALL_RES_ID = "icoSmallResId";
private static final String UPDATE_PROGRESS = "updateProgress";
private static final String STORE_DIR = "storeDir";
private static final String DOWNLOAD_NOTIFICATION_FLAG = "downloadNotificationFlag";
private static final String DOWNLOAD_SUCCESS_NOTIFICATION_FLAG = "downloadSuccessNotificationFlag";
private static final String DOWNLOAD_ERROR_NOTIFICATION_FLAG = "downloadErrorNotificationFlag";
private static final String IS_SEND_BROADCAST = "isSendBroadcast";
private String downloadUrl;
private int icoResId; //default app ico
private int icoSmallResId;
private int updateProgress; //update notification progress when it add number
private String storeDir; //default sdcard/Android/package/update
private int downloadNotificationFlag;
private int downloadSuccessNotificationFlag;
private int downloadErrorNotificationFlag;
private boolean isSendBroadcast;
private UpdateProgressListener updateProgressListener;
private LocalBinder localBinder = new LocalBinder();
/**
* Class used for the client Binder.
*/
public class LocalBinder extends Binder
/**
* set update progress call back
*
* @param listener
*/
public void setUpdateProgressListener(UpdateProgressListener listener)
UpdateService.this.setUpdateProgressListener(listener);
private boolean startDownload;//开始下载
private int lastProgressNumber;
private NotificationCompat.Builder builder;
private NotificationManager manager;
private int notifyId;
private String appName;
private LocalBroadcastManager localBroadcastManager;
private Intent localIntent;
private DownloadApk downloadApkTask;
/**
* whether debug
*/
public static void debug()
DEBUG = true;
private Intent installIntent(Context context, String path)
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addCategory(Intent.CATEGORY_DEFAULT);
String fileProviderAuthority = getFileProviderAuthority(context);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && null!= fileProviderAuthority)
Uri fileUri = FileProvider.getUriForFile(context, fileProviderAuthority, new File(path));
intent.setDataAndType(fileUri, "application/vnd.android.package-archive");
grantUriPermission(getPackageName(), fileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
else
intent.setDataAndType(Uri.fromFile(new File(path)), "application/vnd.android.package-archive");
return intent;
/**
* 获取FileProvider的auth
*/
private static String getFileProviderAuthority(Context context)
try
for (ProviderInfo provider : context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_PROVIDERS).providers)
if (FileProvider.class.getName().equals(provider.name) && provider.authority.endsWith(".update_app.file_provider"))
return provider.authority;
catch (PackageManager.NameNotFoundException ignore)
return null;
private static Intent webLauncher(String downloadUrl)
Uri download = Uri.parse(downloadUrl);
Intent intent = new Intent(Intent.ACTION_VIEW, download);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
return intent;
private static String getSaveFileName(String downloadUrl)
if (downloadUrl == null || TextUtils.isEmpty(downloadUrl))
return System.currentTimeMillis() + ".apk";
return downloadUrl.substring(downloadUrl.lastIndexOf("/"));
private static File getDownloadDir(UpdateService service)
File downloadDir = null;
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED))
if (service.storeDir != null)
downloadDir = new File(Environment.getExternalStorageDirectory(), service.storeDir);
else
downloadDir = new File(service.getExternalCacheDir(), "update");
else
downloadDir = new File(service.getCacheDir(), "update");
if (!downloadDir.exists())
downloadDir.mkdirs();
return downloadDir;
@Override
public void onCreate()
super.onCreate();
appName = getApplicationName();
@Override
public int onStartCommand(Intent intent, int flags, int startId)
if (!startDownload && intent != null)
startDownload = true;
downloadUrl = intent.getStringExtra(URL);
icoResId = intent.getIntExtra(ICO_RES_ID, DEFAULT_RES_ID);
icoSmallResId = intent.getIntExtra(ICO_SMALL_RES_ID, DEFAULT_RES_ID);
storeDir = intent.getStringExtra(STORE_DIR);
updateProgress = intent.getIntExtra(UPDATE_PROGRESS, UPDATE_NUMBER_SIZE);
downloadNotificationFlag = intent.getIntExtra(DOWNLOAD_NOTIFICATION_FLAG, 0);
downloadErrorNotificationFlag = intent.getIntExtra(DOWNLOAD_ERROR_NOTIFICATION_FLAG, 0);
downloadSuccessNotificationFlag = intent.getIntExtra(DOWNLOAD_SUCCESS_NOTIFICATION_FLAG, 0);
isSendBroadcast = intent.getBooleanExtra(IS_SEND_BROADCAST, false);
if (DEBUG)
Log.d(TAG, "downloadUrl: " + downloadUrl);
Log.d(TAG, "icoResId: " + icoResId);
Log.d(TAG, "icoSmallResId: " + icoSmallResId);
Log.d(TAG, "storeDir: " + storeDir);
Log.d(TAG, "updateProgress: " + updateProgress);
Log.d(TAG, "downloadNotificationFlag: " + downloadNotificationFlag);
Log.d(TAG, "downloadErrorNotificationFlag: " + downloadErrorNotificationFlag);
Log.d(TAG, "downloadSuccessNotificationFlag: " + downloadSuccessNotificationFlag);
Log.d(TAG, "isSendBroadcast: " + isSendBroadcast);
notifyId = startId;
buildNotification();
buildBroadcast();
downloadApkTask = new DownloadApk(this);
downloadApkTask.execute(downloadUrl);
return super.onStartCommand(intent, flags, startId);
@Nullable
@Override
public IBinder onBind(Intent intent)
return localBinder;
@Override
public boolean onUnbind(Intent intent)
return true;
public void setUpdateProgressListener(UpdateProgressListener updateProgressListener)
this.updateProgressListener = updateProgressListener;
@Override
public void onDestroy()
if (downloadApkTask != null)
downloadApkTask.cancel(true);
if (updateProgressListener != null)
updateProgressListener = null;
localIntent = null;
builder = null;
super.onDestroy();
public String getApplicationName()
PackageManager packageManager = null;
ApplicationInfo applicationInfo = null;
try
packageManager = getApplicationContext().getPackageManager();
applicationInfo = packageManager.getApplicationInfo(getPackageName(), 0);
catch (PackageManager.NameNotFoundException e)
applicationInfo = null;
String applicationName =
(String) packageManager.getApplicationLabel(applicationInfo);
return applicationName;
private void buildBroadcast()
if (!isSendBroadcast)
return;
localBroadcastManager = LocalBroadcastManager.getInstance(this);
localIntent = new Intent(ACTION);
private void sendLocalBroadcast(int status, int progress)
if (!isSendBroadcast || localIntent == null)
return;
localIntent.putExtra(STATUS, status);
localIntent.putExtra(PROGRESS, progress);
localBroadcastManager.sendBroadcast(localIntent)以上是关于Android 9.0自动更新 安装包解析错误 java.lang.SecurityException: Permission Denial的主要内容,如果未能解决你的问题,请参考以下文章