Android7.0下载apk后安装出现解析包错误

5187235268b5493ee90307a133cc8d10.jpg

这个问题困扰了我整整一天时间,所以决定记录下来!
我要说的是这个错误其实并不是因为7.0私密文件夹权限引起的错误,因为AndroidN出了这么久,大家也都应该对FileProvider有所了解了。

1.下载

我采用的自然是简单的系统自带的DownloadManager方式来下载

 /**
     * 下载APK文件
     */
    private void downloadApk(String downloadUrl) {
        clearApk(getString(R.string.app_name_en)+".apk");
        //TODO 1.封装下载请求
        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downloadUrl));
        //TODO 2.下载标题,描述
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        request.setTitle(getString(R.string.app_name_en));
        request.setDescription(getString(R.string.app_name_en)+"下载");
        // TODO 3.设置下载文件的保存位置
        request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,getString(R.string.app_name_en)+".apk");
        // TODO 4.获取下载管理器服务的实例, 添加下载任务
        DownloadManager manager = (DownloadManager)getSystemService(Context.DOWNLOAD_SERVICE);
        manager.enqueue(request);// 将下载请求加入下载队列, 返回一个下载ID
    }

    public static File clearApk(String apkName) {
        File apkFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), apkName);
        if (apkFile.exists()) {
            apkFile.delete();
        }
        return apkFile;
    }
2.注册广播
<receiver android:name="cq.cake.http.DownloadManagerReceiver">
            <intent-filter>
                <!-- 配置 点击通知 和 下载完成 两个 action -->
                <action android:name="android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED"/>
                <action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
            </intent-filter>
        </receiver>
3.广播通知下载完毕,并开始安装
public class DownloadManagerReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();

        if (DownloadManager.ACTION_NOTIFICATION_CLICKED.equals(action)) {
            L.i("用户点击了通知");
            // 点击下载进度通知时, 对应的下载ID以数组的方式传递
            long[] ids = intent.getLongArrayExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS);
            L.i("ids: " + Arrays.toString(ids));
        } else if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
            /*
             * 获取下载完成对应的下载ID, 这里下载完成指的不是下载成功, 下载失败也算是下载完成,
             * 所以接收到下载完成广播后, 还需要根据 id 手动查询对应下载请求的成功与失败.
             */
            long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1L);
            L.i("id: " + downloadId);
            // 根据获取到的ID,使用上面第3步的方法查询是否下载成功
            DownloadManager manager = (DownloadManager) MyApplication.getContext().getSystemService(Context.DOWNLOAD_SERVICE);
            DownloadManager.Query query = new DownloadManager.Query();
            query.setFilterById(downloadId);
            Cursor cursor = manager.query(query);
            if (!cursor.moveToFirst()) {
                cursor.close();
                return;
            }
            int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
            String localFilename;
            if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
                localFilename = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
            }else{
                localFilename = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
            }
            if (status == DownloadManager.STATUS_SUCCESSFUL) {
                T.showLong(context,"下载完成,点击通知栏安装!");
                System.out.println("下载成功, 打开文件, 文件路径: " + localFilename);
//                setPermission(localFilename);
                installApk(context,localFilename);
            }
        }
    }


    /**
     * 安装APK
     */
    private void installApk(Context context,String filePath) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        File file = new File(Environment.getExternalStorageDirectory()+"/"+Environment.DIRECTORY_DOWNLOADS,context.getString(R.string.app_name_en)+".apk");
        if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
//            File file = new File(context.getExternalFilesDir(null)+"/"+ Environment.DIRECTORY_DOWNLOADS,context.getString(R.string.app_name_en)+".apk");
            Uri apkUri= FileProvider.getUriForFile(context, "cq.cake.shopingmarket.three.fileprovider", file);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            L.i("要安装的apk路径为=="+apkUri.getPath());
            intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
        }else{
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
        }
        context.startActivity(intent);
    }

    /**
     * 提升读写权限
     * @param filePath 文件路径
     * @return
     * @throws IOException
     */
//    public static void setPermission(String filePath)  {
//        String command = "chmod " + "777" + " " + filePath;
//        Runtime runtime = Runtime.getRuntime();
//        try {
//            runtime.exec(command);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//    }

}

由于今天主要是说出现错误的原因,所以三步就先把正确的代码贴了出来。这个问题也困扰了我一整天。其实最后证实主要原因还是路径不正确导致的,为什么会犯这么低级的错误呢!因为我把这个解析包错误的原因看得太宽泛了。

1.修正一,百度了这个错误,有的人说打的包不正确,应该都是debug包或正式包,但我试了试问题依旧
2.修正二,有的人说是因为AndroidStudio打v1和v2包不兼容,所以有这个问题,我想说我一直都是用的v1的方式打包
3.修正三,有的人说你的apk就不完整,但是我点击通知栏下载好的,却可以安装,说明包没有问题
4.修正四,有的人说你的7.0的系统需要fileprovider的方式来访问,我想说如果不用FileProvider,来访问我的应用直接就死了,所以也不是这个原因
5.修正五,有的说是权限不够,Linux需要提权,所以我在使用FileProvider前,调用了如下方法来提升权限,发现问题依旧

 /**
     * 提升读写权限
     * @param filePath 文件路径
     * @return
     * @throws IOException
     */
//    public static void setPermission(String filePath)  {
//        String command = "chmod " + "777" + " " + filePath;
//        Runtime runtime = Runtime.getRuntime();
//        try {
//            runtime.exec(command);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//    }

6.修正六,最后只能确定是在路径上有问题,我就一步一步的打印路径,看看到底哪里有问题,下载的路径,广播后通知的路径,安装前的路径,最后发现安装的路径居然和广播的路径不同

修正.png

居然在安装的时候在前面多了一个download,这个是在file_paths里面的别名,意义就是隐藏掉前面的路径名称,最开始我以为是名称不是Download引起的,所以后面加个一个download的root-path,却发现这样毫无作用。

所以最关键的问题还是出现installApk这个方法里面,最开始我是通过广播得到的下载文件的路径和名称:

 String localFilename;
            if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
                localFilename = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
            }else{
                localFilename = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
            }

然后把这个路径名称传递进入installApk方法,但是在这个安装方法里面由于要适配7.0,所以使用了FileProvider来获取Uri,就导致了路径被变更了,但是却不知道如何来修改这个路径,毕竟广播过来的这个路径确实是正确的,只是因为使用了FileProvider而导致的路径不正确(如上图所示)。最后在群里面询问了遇到同样问题的同学,才知道他是自己拼的File:

        File file = new File(Environment.getExternalStorageDirectory()+"/"+Environment.DIRECTORY_DOWNLOADS,context.getString(R.string.app_name_en)+".apk");

这样拼接后果然出现了,期待已久的安装界面!到此这个问题总算解决了,所以广播后查询的下载目录localFilename也就失去了意思,也可以省略了!唯一有用的就是下载完成后是否真正成功的状态,因为下载完成并不代表下载成功,记录下来给遇到同样困惑的同学!

int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
if (status == DownloadManager.STATUS_SUCCESSFUL) {
                T.showLong(context,"下载完成,点击通知栏安装!");
                installApk(context);
            }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容