当前位置:   article > 正文

安装apk解析包时出现错误(应用内更新)_解析错误解析程序包时出现问题.

解析错误解析程序包时出现问题.

最近遇到一个问题,有个别用户在应用内更新版本会出现解析包失败的情况,而且有的机型还是必现,浏览器下载就没问题,应用内就有问题,这就很让人费解,之前一直没关注过这种情况,但是用户就是上帝,有问题必须得解决啊!后来查了一些资料,发现想要解决这种情况还是有迹可循的,下面是总结的几种可能出现的情况,做了一些总结。

1、JDK版本问题,比如jdk1.6环境下打包可正常安装,1.7环境打的包就不行

解决办法是,需要在签名程序 jarsigner 增加如下参数

-digestalg SHA1 -sigalg MD5withRSA
  • 1

此参数对 JDK 1.6 没有影响。

2、系统版本不兼容,比如apk支持系统版本高于用户手机系统版本
3、apk包不完整,有些手机自带的下载工具不具有断点续传功能,因此在下载过程中可能发生下载不完全、程序部分丢失等情况。
4、当前手机不支持中文名称或路径,不支持长文件名
5、手机内存不足或手机内存卡接触不良
6、指定文件路径不存在,一种典型的情况就是在网上已经公布RE管理器设置不当造成的程序无法安装:解决办法是:进入RE管理器,点击“设置”—>“一键设置”—>“主文件夹选项”,如果将其设置成“sdcard\ ”就会出现“解析包出现问题”的错误提示,而如果将其设置“\ ”就可以成功安装,建议诸位试试!
7、apk安装器可能不兼容或示安装。该类情况通常多发生在进行ROM的手机当中,由于手机经过刷机之后,有点系统必备软件例如“绿巨人”、“install”等程序由于精简的需要而没有被安装上,导致apk程序无法正常安装。解决的办法是到安卓市场上下载相关的apk安装器,然后通过apk安装器安装apk应用程序。
8、在打包的时候我们使用了V2签名导致无法进行安装。

Android 7.0 引入一项新的应用签名方案 APK Signature Scheme v2,它能提供更快的应用安装时间和更多针对未授权 APK 文件更改的保护。在默认情况下,Android Studio 2.2 和 Android Plugin for Gradle 2.2 会使用 APK Signature Scheme v2 和传统签名方案来签署应用。
这项新方案并非强制性的,如果应用在使用 APK Signature Scheme v2 时不能正确开发,可以停用这项新方案。禁用过程会导致 Android Studio 2.2 和 Android Plugin for Gradle 2.2 仅使用传统签名方案来签署应用。要仅用传统方案签署,打开模块级 build.gradle 文件,然后将行 v2SigningEnabled false 添加到版本签名配置中:

android {
    …
    defaultConfig { … }
    signingConfigs {
        release {
            storeFile file(“myreleasekey.keystore”)
            storePassword “password”
            keyAlias “MyReleaseKey”
            keyPassword “password”
            v2SigningEnabled false
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

根据官方文档,就是在我们的gradle文件里的相应位置添加这行代码

v2SigningEnabled false
  • 1
9、在7.0上使用系统服务去下载apk并且试图安装时,有可能由于权限问题导致安装失败。

每个Android版本的发布,对于安全性问题的要求越来越高,也为Android程序员增加了额外的工作量。Android6.0引入动态权限控制(Runtime Permissions),Android7.0引入私有目录被限制访问和StrictMode API 。私有目录被限制访问是指在Android7.0中为了提高应用的安全性,在7.0上应用私有目录将被限制访问,这与iOS的沙盒机制类似。StrictMode API是指禁止向你的应用外公开 file:// URI。 如果一项包含文件 file:// URI类型 的 Intent 离开你的应用,则会报出异常。
以下是我原来在7.0上出问题的代码:

Intent install = new Intent(Intent.ACTION_VIEW);
install.setDataAndType(Uri.fromFile(new File(fileName)), "application/vnd.android.package-archive");
install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(install);
  • 1
  • 2
  • 3
  • 4

从代码中可以看出,Uri.fromFile导致我们在7.0上出现了问题,它其实就是生成一个file://URL。这就是为什么在下载完成后,调用这段代码去安装的时候出错,因为一旦我们通过这种办法打开系统安装器,就认为file:// URI类型的 Intent 离开我的应用,这样程序就会发生异常;而我们手动去把安装包覆盖原来的旧包则没有问题。

解决方案将使用FileProvider,它的步骤是:

第一步:
在AndroidManifest.xml中注册provider,provider可以向应用外提供数据。

<provider
   android:name="android.support.v4.content.FileProvider"
   android:authorities="com.app.pro.fileprovider"
   android:grantUriPermissions="true"
   android:exported="false">
   <meta-data
       android:name="android.support.FILE_PROVIDER_PATHS"
       android:resource="@xml/file_paths" />
</provider>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

其中com.app.pro是应用包名。

第二步:
在res/xml/file_paths.xml创建文件。 内容为:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <paths>
        <external-path path="" name="download"/>
    </paths>
</resources>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

第三步:

String fileName = cursor.getString(fileNameIdx);//承接我的代码,filename指获取到了我的文件相应路径
if (fileName != null) {
    if (fileName.endsWith(".apk")) {
        if(Build.VERSION.SDK_INT>=24) {//判读版本是否在7.0以上
            File file= new File(fileName);
            Uri apkUri = FileProvider.getUriForFile(context, "com.dafangya.app.pro.fileprovider", file);//在AndroidManifest中的android:authorities值
            Intent install = new Intent(Intent.ACTION_VIEW);
            install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//添加这一句表示对目标应用临时授权该Uri所代表的文件
            install.setDataAndType(apkUri, "application/vnd.android.package-archive");
            context.startActivity(install);
        } else{
            Intent install = new Intent(Intent.ACTION_VIEW);
            install.setDataAndType(Uri.fromFile(new File(fileName)), "application/vnd.android.package-archive");
            install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(install);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

因为对于7.0以下的设备,还是走以前的逻辑,所以上面的代码进行分情况讨论,6.0及其以下的设备还是走以前的逻辑。

第四步
按照大部分教程来说,第四步其实是不存在的,但是在我的项目中,运行到第三步中的代码时,还是报错了,错误如下:

java.lang.RuntimeException: Error receiving broadcast Intent { act=android.intent.action.DOWNLOAD_COMPLETE flg=0x10 pkg=com.dafangya.app.pro (has extras) } in com.b.b.a.a.e$1@457cfd2
    at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:1229)
    at android.os.Handler.handleCallback(Handler.java:755)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:156)
    at android.app.ActivityThread.main(ActivityThread.java:6524)
    at java.lang.reflect.Method.invoke(Method.java)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:941)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:831)
Caused by: java.lang.IllegalArgumentException: Failed to find configured root that contains /data/data/com.android.providers.downloads/cache/product_other_V1.4.8ceshi.apk
    at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:678)
    at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:377)
    at com.example.xh.toolsdk.umeng.Downloads$1.onReceive(Downloads.java:95)
    at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:1219)
    ... 7 more
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

由Caused by: java.lang.IllegalArgumentException: Failed to find configured root that contains…可见应该是我们的安装包目录出现了问题。因为使用我们当前方法的时候,我们主要通过系统提供的DownloadManager进行下载,我们不妨从下载角度来看我们是否可以自己设置一个下载目录。
代码如下:

public void submit(String name, String url) {
    DownloadManager download = getDownLoadManager();
        Uri uri = Uri.parse(url);
        DownloadManager.Request request = new DownloadManager.Request(uri);
        request.setTitle(String.valueOf(name));
        //设置下载存放的文件夹和文件名字
        request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "dafangya_house.apk");
        try {
            downloadId = download.enqueue(request);
        } catch (Exception e) {
            e.printStackTrace();
        }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

我在原来的代码中添加了这一行:

request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, “wanj.apk”);
  • 1

设置了它的下载路径,在进行测试的时候,发现无论在7.0还是低版本的设备上都可以正常下载更新了。

10、sever返回的mimetype有问题,导致打开时,发往其他app的Intent不能被正常处理。例如无法安装apk文件

此错误日志一般类似这样

DownloadManager:Failed to start Intent { act=Android.intent.action.VIEWdat=content://downloads/all_downloads/9 typ=application/octet-stream flg=0x3 }:android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEWdat=content://downloads/all_downloads/9 typ=application/octet-stream flg=0x3 }
  • 1

从log信息可以看出:mime typ=application/octet-stream 不能被处理。

主要原因是:下载apk时,server返回application/octet-stream,不是标准的mimetype: application/vnd.android.package-archive

解决方案:
先确认无法打开文件的正确mimetype,然后在DownloadHandler.Java中的DownloadStartNoStream()作特殊处理。将sever返回错误的mime强
制修正成正确的mime type即可。下面给出以无法打开apk为例的修改方案,同理,其他格式的文件也是类似的。
修改文件:

\packages\apps\Browser\src\com\android\browser\DownloadHandler.Java
  • 1

修改方法:

onDownloadStartNoStream()
  • 1

具体修改:

public static void onDownloadStartNoStream(Activity activity,String url, String userAgent, String contentDisposition, String mimetype,String referer, boolean privateBrowsing, long contentLength) { 
String filename = URLUtil.guessFileName(url, contentDisposition,mimetype); 
Xlog.d(XLOGTAG, “Guess file name is: ” + filename + ” mimetypeis: ” + mimetype);

// modify start: change Mime for apk 
if (filename.endsWith(“.apk”) &&mimetype.equals(“application/octet-stream”)) 
{ 
mimetype =”application/vnd.android.package-archive”; 
} 
// modify end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
11、某些机型,比如华为、三星有问题

AndroidManifest.xml中缺少targetSdkVersion

12、下载的apk从代码里跳转到安装界面进行升级安装的时候,安装完成以后一闪而过回到了Android桌面,但是应用又安装成功了,从应用列表启动确实是新版本的应用。

为什么会出现这样的情况呢?这种现象会给用户带来很不好的体验,让用户认为是安装失败了。
调用升级安装的代码是这样的

Uri uri = Uri.fromFile(new File(filePath));
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri,"application/vnd.android.package-archive");
startActivity(intent);
  • 1
  • 2
  • 3
  • 4

使用该方法,安装完成后,安装界面就关闭了,不会看到一个包含完成和打开按钮的界面。
解决办法如下:

Uri uri = Uri.fromFile(new File(filePath));
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
android.os.Process.killProcess(android.os.Process.myPid());
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

android.os.Process.killProcess(android.os.Process.myPid());如果不加,最后不会提示完成、打开。
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);如果不加,最后安装完成,点打开,无法打开新版本应用。

12、手机系统内部还有之前安装包的残留文件,导致再次安装时无法覆盖安装。

解决方案:应用完全卸载(设备连接电脑后,在调试模式下通过命令行:

adb uninstall <com.xxx.xxx(包名)>来卸载应用)。
  • 1

很明显,不能要求用户这么做。

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号