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

c7aca7c7d5d9

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.注册广播

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

c7aca7c7d5d9

修正.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);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值