最近遇到一個問題,有個別用戶在應(yīng)用內(nèi)更新版本會出現(xiàn)解析包失敗的情況,而且有的機型還是必現(xiàn),瀏覽器下載就沒問題,應(yīng)用內(nèi)就有問題,這就很讓人費解,之前一直沒關(guān)注過這種情況,但是用戶就是上帝,有問題必須得解決啊!后來查了一些資料,發(fā)現(xiàn)想要解決這種情況還是有跡可循的,下面是總結(jié)的幾種可能出現(xiàn)的情況,做了一些總結(jié)。
1、JDK版本問題解析包程序出現(xiàn)錯誤,比如jdk1.6環(huán)境下打包可正常安裝,1.7環(huán)境打的包就不行
解決辦法是,需要在簽名程序 增加如下參數(shù)
-digestalg SHA1 -sigalg MD5withRSA
此參數(shù)對 JDK 1.6 沒有影響。
2、系統(tǒng)版本不兼容,比如apk支持系統(tǒng)版本高于用戶手機系統(tǒng)版本 3、apk包不完整,有些手機自帶的下載工具不具有斷點續(xù)傳功能,因此在下載過程中可能發(fā)生下載不完全、程序部分丟失等情況。 4、當前手機不支持中文名稱或路徑,不支持長文件名 5、手機內(nèi)存不足或手機內(nèi)存卡接觸不良 6、指定文件路徑不存在,一種典型的情況就是在網(wǎng)上已經(jīng)公布RE管理器設(shè)置不當造成的程序無法安裝:解決辦法是:進入RE管理器,點擊“設(shè)置”—>“一鍵設(shè)置”—>“主文件夾選項”,如果將其設(shè)置成“\ ”就會出現(xiàn)“解析包出現(xiàn)問題”的錯誤提示,而如果將其設(shè)置“\ ”就可以成功安裝,建議諸位試試! 7、apk安裝器可能不兼容或示安裝。該類情況通常多發(fā)生在進行ROM的手機當中,由于手機經(jīng)過刷機之后,有點系統(tǒng)必備軟件例如“綠巨人”、“”等程序由于精簡的需要而沒有被安裝上,導(dǎo)致apk程序無法正常安裝。解決的辦法是到安卓市場上下載相關(guān)的apk安裝器,然后通過apk安裝器安裝apk應(yīng)用程序。 8、在打包的時候我們使用了V2簽名導(dǎo)致無法進行安裝。
7.0 引入一項新的應(yīng)用簽名方案 APK v2,它能提供更快的應(yīng)用安裝時間和更多針對未授權(quán) APK 文件更改的保護。在默認情況下, 2.2 和 for 2.2 會使用 APK v2 和傳統(tǒng)簽名方案來簽署應(yīng)用。
這項新方案并非強制性的,如果應(yīng)用在使用 APK v2 時不能正確開發(fā),可以停用這項新方案。禁用過程會導(dǎo)致 2.2 和 for 2.2 僅使用傳統(tǒng)簽名方案來簽署應(yīng)用。要僅用傳統(tǒng)方案簽署,打開模塊級 build. 文件,然后將行 false 添加到版本簽名配置中:
android {
…
defaultConfig { … }
signingConfigs {
release {
storeFile file(“myreleasekey.keystore”)
storePassword “password”
keyAlias “MyReleaseKey”
keyPassword “password”
v2SigningEnabled false
}
}
}
根據(jù)官方文檔,就是在我們的文件里的相應(yīng)位置添加這行代碼
v2SigningEnabled false
9、在7.0上使用系統(tǒng)服務(wù)去下載apk并且試圖安裝時,有可能由于權(quán)限問題導(dǎo)致安裝失敗。
每個版本的發(fā)布,對于安全性問題的要求越來越高,也為程序員增加了額外的工作量。.0引入動態(tài)權(quán)限控制( ),.0引入私有目錄被限制訪問和 API 。私有目錄被限制訪問是指在.0中為了提高應(yīng)用的安全性,在7.0上應(yīng)用私有目錄將被限制訪問,這與iOS的沙盒機制類似。 API是指禁止向你的應(yīng)用外公開 file:// URI。 如果一項包含文件 file:// URI類型 的 離開你的應(yīng)用,則會報出異常。
以下是我原來在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);
從代碼中可以看出,Uri.導(dǎo)致我們在7.0上出現(xiàn)了問題,它其實就是生成一個file://URL。這就是為什么在下載完成后,調(diào)用這段代碼去安裝的時候出錯,因為一旦我們通過這種辦法打開系統(tǒng)安裝器,就認為file:// URI類型的 離開我的應(yīng)用,這樣程序就會發(fā)生異常;而我們手動去把安裝包覆蓋原來的舊包則沒有問題。
解決方案將使用,它的步驟是:
第一步:
在.xml中注冊,可以向應(yīng)用外提供數(shù)據(jù)。
<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>
其中com.app.pro是應(yīng)用包名。
第二步:
在res/xml/.xml創(chuàng)建文件。 內(nèi)容為:
<resources>
<paths>
<external-path path="" name="download"/>
paths>
resources>
第三步:
String fileName = cursor.getString(fileNameIdx);//承接我的代碼,filename指獲取到了我的文件相應(yīng)路徑
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);//添加這一句表示對目標應(yīng)用臨時授權(quán)該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);
}
}
}
因為對于7.0以下的設(shè)備,還是走以前的邏輯,所以上面的代碼進行分情況討論,6.0及其以下的設(shè)備還是走以前的邏輯。
第四步
按照大部分教程來說,第四步其實是不存在的,但是在我的項目中,運行到第三步中的代碼時,還是報錯了,錯誤如下:
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
由 by: java.lang.tion: to find root that …可見應(yīng)該是我們的安裝包目錄出現(xiàn)了問題。因為使用我們當前方法的時候,我們主要通過系統(tǒng)提供的進行下載,我們不妨從下載角度來看我們是否可以自己設(shè)置一個下載目錄。
代碼如下:
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));
//設(shè)置下載存放的文件夾和文件名字
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "dafangya_house.apk");
try {
downloadId = download.enqueue(request);
} catch (Exception e) {

e.printStackTrace();
}
}
我在原來的代碼中添加了這一行:
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, “wanj.apk”);
設(shè)置了它的下載路徑,在進行測試的時候,發(fā)現(xiàn)無論在7.0還是低版本的設(shè)備上都可以正常下載更新了。
10、sever返回的有問題,導(dǎo)致打開時,發(fā)往其他app的不能被正常處理。例如無法安裝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 }
從log信息可以看出:mime typ=/octet- 不能被處理。
主要原因是:下載apk時,返回/octet-,不是標準的: /vnd..-
解決方案:
先確認無法打開文件的正確,然后在.Java中的m()作特殊處理。將sever返回錯誤的mime強
制修正成正確的mime type即可。下面給出以無法打開apk為例的修改方案,同理,其他格式的文件也是類似的。
修改文件:
\packages\apps\Browser\src\com\android\browser\DownloadHandler.Java
修改方法:
onDownloadStartNoStream()
具體修改:
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
11、某些機型解析包程序出現(xiàn)錯誤,比如華為、三星有問題
.xml中缺少
12、下載的apk從代碼里跳轉(zhuǎn)到安裝界面進行升級安裝的時候,安裝完成以后一閃而過回到了桌面,但是應(yīng)用又安裝成功了,從應(yīng)用列表啟動確實是新版本的應(yīng)用。
為什么會出現(xiàn)這樣的情況呢?這種現(xiàn)象會給用戶帶來很不好的體驗,讓用戶認為是安裝失敗了。
調(diào)用升級安裝的代碼是這樣的
Uri uri = Uri.fromFile(new File(filePath));
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri,"application/vnd.android.package-archive");
startActivity(intent);
使用該方法,安裝完成后,安裝界面就關(guān)閉了,不會看到一個包含完成和打開按鈕的界面。
解決辦法如下:
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());
.os..(.os..myPid());如果不加,最后不會提示完成、打開。
.(.SK);如果不加,最后安裝完成,點打開,無法打開新版本應(yīng)用。
12、手機系統(tǒng)內(nèi)部還有之前安裝包的殘留文件,導(dǎo)致再次安裝時無法覆蓋安裝。
解決方案:應(yīng)用完全卸載(設(shè)備連接電腦后,在調(diào)試模式下通過命令行:
adb uninstall <com.xxx.xxx(包名)>來卸載應(yīng)用)。
很明顯,不能要求用戶這么做。