天天看點

android 8.0版本安裝,記 Android 7.0 8.0版本更新安裝遇到的坑

前言:7.0版本更新FileProvider的使用網上很多就不講了,本文主要講述這次發版遇到的一系列坑。。。

前天喜滋滋的釋出了新版本,木有想到昨天就出現問題了,那就是Android 8.0系統居然不能下載下傳安裝,或是下載下傳成功了也沒有跳出應用安裝界面。于是我不管三七二十一先百度了一波,大概意思就是Android 8.0的系統中,“未知來源應用權限”的開關被移除掉了,取而代之的是未知來源應用的管理清單,如果你想要安裝某個被自己所信任的開發者的app,則需要在每一次都手動授權“安裝未知應用”的許可。

網上的解決其實很簡單:

1.在AndroidManifest.xml檔案中,添加REQUEST_INSTALL_PACKAGES權限

2.在打開安裝包的代碼中添加“相容Android 8.0”的代碼

//相容8.0

boolean installAllowed;

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

installAllowed = context.getPackageManager().canRequestPackageInstalls();

if (installAllowed) {

installApk(file);

} else {

Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, Uri.parse("package:" + context.getPackageName()));

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

context.startActivity(intent);

installApk(file);

return;

}

} else {

installApk(file);

}

//安裝apk,相容7.0

protected void installApk(File file) {

if (!file.exists()) {

return;

}

Intent intent = new Intent(Intent.ACTION_VIEW);

//版本在7.0以上是不能直接通過uri通路的

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

//參數1 上下文, 參數2 Provider主機位址和清單檔案中保持一緻 參數3 共享的檔案

Uri apkUri =

FileProvider.getUriForFile(context, "com.xxx.fileProvider", file);

//添加這一句表示對目标應用臨時授權該Uri所代表的檔案

intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

intent.setDataAndType(apkUri, "application/vnd.android.package-archive");

} else {

intent.setDataAndType(Uri.fromFile(file),

"application/vnd.android.package-archive");

}

// intent.setDataAndType(Uri.parse("file://" + file.toString()), "application/vnd.android.package-archive");

// 由于沒有在Activity環境下啟動Activity,設定下面的标簽

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

context.startActivity(intent);

}

在這個過程中我還遇到了一個坑,那就是canRequestPackageInstalls一直傳回false。查了資料才發現targetSdkVersion是26以上才能擷取正确的canRequestPackageInstalls,否則就一直傳回false。(ps:我之前的targetSdkVersion是24)。

做完這兩步後可以下載下傳并自動跳轉到未知來源應用權限界面,你以為這樣就完了嗎?并沒有!!!

運作了幾次後直接下載下傳進度沒有了,換言之就是下載下傳不了! what??? 一陣煩躁。。。

想不到到底是哪兒出現問題了呢,剛剛還好好的運作,咋地突然就不能下載下傳了。。。

檢視了報錯日志,如下:

android 8.0版本安裝,記 Android 7.0 8.0版本更新安裝遇到的坑

報錯日志.png

意思就是使用者拒絕了權限,可是我明明一開始就動态設定權限允許了呀,為什麼還會出現這個??不信邪的我特意去看這個APP下看了權限,确實存儲權限是開了的呀,一臉懵逼。。。

第一感覺會不會又是Android 8.0的問題呢,結果确實是,是因為代碼中動态申請的其實是READ_EXTERNAL_STORAGE讀存儲權限,這在Android O(Android 8.0)之前是沒有任何問題的,因為讀寫是一組權限,同屬存儲權限,隻要申請了同組權限中的一個,同組中的其他在清單檔案中列出了的權限也就被授予了。但是Android O(Android 8.0)運作時權限有了變動,就是系統隻會授予應用明确請求的權限,

然而一旦使用者為應用授予某個權限,則所有後續對該權限組中權限的請求都将被自動準許,但是還是需要去申請,這點和Android O(Android 8.0)之前不同。

由于這裡建立下載下傳檔案,實際上是往存儲中寫檔案,需要寫存儲權限WRITE_EXTERNAL_STORAGE,于是将代碼點選更新時申請READ_EXTERNAL_STORAGE改為申請WRITE_EXTERNAL_STORAGE。運作測試,APK檔案是可以下載下傳成功了。至于之前幾次為什麼可以下載下傳,我還是想不明白,可能和targetSdkVersion有關。

如果你以為我這次的坑徹底結束了,那你就錯了!!!因為這些解決完之後結果解析包安裝失敗了,,why???

查了資料大體就是Android Studio打包問題,現在Android Studio打包出現了兩個選擇signature versions:V1(Jar Signature) and V2(Full APK Signature) 。以下是官方說法:

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 {

debug {

storeFile file("./xxx.keystore")

storePassword 'password'

keyAlias 'xxx'

keyPassword 'password'

}

release {

storeFile file("./xxx.keystore")

storePassword 'password'

keyAlias 'xxx'

keyPassword 'password'

v2SigningEnabled false

}

}

根據官方文檔,就是在我們的gradle檔案裡的相應位置添加這行代碼

v2SigningEnabled false

but!!!我添加了之後還是出現了解析包安裝失敗,,藍瘦香菇。。。路漫漫~~~隻能繼續摸索

當發現是 7.0 系統上才會出現的問題之後,再聯系報錯資訊,很容易就想到 FileProvider 的權限問題,然而并沒有什麼用,我還是不知道怎麼回事。對比之前實作的版本更新的代碼,定位到 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)這句代碼,因為我把intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)放在了intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)前面,當把intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)這句話放在intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)前面,就是正常的。

這是因為對 setFlags() 和 addFlags() 認知不清,錯誤使用導緻的,最後,将 setFlags()操作放在 addFlags() 之前解決了這個問題。

//安裝apk,相容7.0

protected void installApk(File file) {

if (!file.exists()) {

return;

}

Intent intent = new Intent(Intent.ACTION_VIEW);

// 由于沒有在Activity環境下啟動Activity,設定下面的标簽 setFlags要放在addFlags之前

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

//版本在7.0以上是不能直接通過uri通路的

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

//參數1 上下文, 參數2 Provider主機位址和清單檔案中保持一緻 參數3 共享的檔案

Uri apkUri =

FileProvider.getUriForFile(context, "com.xxx.fileProvider", file);

//添加這一句表示對目标應用臨時授權該Uri所代表的檔案

intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

intent.setDataAndType(apkUri, "application/vnd.android.package-archive");

} else {

intent.setDataAndType(Uri.fromFile(file),

"application/vnd.android.package-archive");

}

// intent.setDataAndType(Uri.parse("file://" + file.toString()), "application/vnd.android.package-archive");

context.startActivity(intent);

}

intent.setFlags() 和 intent.addFlags() 的差別

setFlags():為intent 設定特殊的标志,會覆寫 intent 已經設定的所有标志。

public Intent setFlags(int flags) {

mFlags = flags;

return this;

}

addFlags():為intent 添加特殊的标志,不會覆寫,隻會追加。

public Intent addFlags(int flags) {

mFlags |= flags;

return this;

}

之前更新Android 7.0并沒有這個問題,應該也是和targetSdkVersion有關。

到此,,此次版本更新遇到的坑總算填完了。。。

總結此次的坑:

一、Android 8.0下載下傳失敗。解決方案:把Android 6.0的動态申請權限READ_EXTERNAL_STORAGE改為申請WRITE_EXTERNAL_STORAGE。

二、Android 8.0下載下傳成功後無法跳到自動更新頁面。解決方案:授權“安裝未知應用”的許可。

三、授權“安裝未知應用”的許可的時候擷取canRequestPackageInstalls一直傳回false。解決方案:targetSdkVersion必須大于等于26(我之前是24)。

四、Android 7.0 8.0 解析包安裝失敗。解決方案:安裝時把intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)這句話放在intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)前面。

好了,,這次真的是講完了,共勉。。。