android 7.0、8.0、9.0適配時遇到更新安裝問題解決

在適配9.0時,遇到了更新包下載完成不能安裝問題,網上找答案,發現了一篇比較全的文章,特此記錄。此文轉載自:https://www.jianshu.com/p/e05f35fbb569

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

網上的解決其實很簡單:
1.在AndroidManifest.xml文件中,添加REQUEST_INSTALL_PACKAGES權限

<uses-permission android:name="android.permission.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??? 一陣煩躁。。。
想不到到底是哪兒出現問題了呢,剛剛還好好的運行,咋地突然就不能下載了。。。
查看了報錯日誌,如下:

 

報錯日誌.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)前面。

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

發佈了19 篇原創文章 · 獲贊 8 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章