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的主要内容,如果未能解决你的问题,请参考以下文章

分批推送!ZenFone5获得Android 9.0更新

解析包错误怎么解决

安卓系统怎么升级 安卓系统升级的几种方法

华为手机 android8.0APP更新时出现安装包解析异常的提示及安装闪退(无反应)问题

离线快速部署Mirantis Openstack 9.0

Android 7.0解析包时出现问题 的解决方案(应用内更新)