Android install apk 兼容至 Android 8

前言

以往安裝apk都是很簡單的方法, Intent 里添加apk的文件就可以調(diào)用系統(tǒng)安裝界面.后來隨著谷歌對安全的重視,從Android 7開始以往的方式都不能用,然而到Android 8 又有改動,相信隨著Android 的發(fā)展,以后的版本也會有改動,崇尚模塊化開發(fā)的我便希望每一個細(xì)小的功能,顆粒度最少的功能都可以由一個模塊來負(fù)責(zé),然后每個項(xiàng)目需要這個功能時調(diào)用這個模塊即可,而這個模塊只需要維護(hù)好自己的兼容性問題便解決所有項(xiàng)目的兼容性問題.

本文思路是提供一個筆者暫時覺得最優(yōu)的方案,然后原理分析提供每個Android 版本的安裝的原理思路

最優(yōu)解決方案 Android Install Apk 庫

最優(yōu)解決方案 : FitAndroid8

首先筆者在解決Android 7 的安裝問題時,遇到系統(tǒng)的私有目錄訪問限制問題,在解決同時感覺谷歌提供的解決方案特別麻煩,需要項(xiàng)目里因?yàn)獒槍ndroid 7 而增加一些文件和AndroidManifest 增加一些代碼,這非常不合理,到了之后的版本或許又不一樣,這些額外的代碼都會帶來維護(hù)的成本,后來搜索很久發(fā)現(xiàn) FitAndroid7 這個庫特別適合,在不用增加自己項(xiàng)目額外的代碼同時,解決Android 7 以下的安裝問題.然后到Android 8 系統(tǒng)時發(fā)現(xiàn)這個庫功能失效,所以筆者便在前者的基礎(chǔ)上稍微修改,讓FitAndroid8能兼容暫時所有版本的安裝,一行代碼完成一個功能,不引入其他額外與項(xiàng)目無關(guān)的代碼和文件.

使用方式:

public void installApk(View view) {
    File file = new File(Environment.getExternalStorageDirectory(), "app-debug.apk");
    Intent intent = new Intent(Intent.ACTION_VIEW);
    // 僅需改變這一行
    FileProvider8.setIntentDataAndType(this,
            intent, "application/vnd.android.package-archive", file, true);
    startActivity(intent);
}

原理分析

筆者的習(xí)慣是把問題用最簡單的方式解決,同時也需要知道其原理,以下內(nèi)容為原理解析.

Android 8 如何安裝apk

Android 8到時有了什么改變以致安裝apk的方法有很大改變呢?

在2017年8月29號的谷歌開發(fā)者博客中寫道 <<在 Android O 中更安全地獲取應(yīng)用>>新的安裝未知應(yīng)用的,Android O 禁用了總是安裝未知應(yīng)用的選擇,改為安裝未知應(yīng)用時提出設(shè)置的提示,減少惡意應(yīng)用通過虛假的安裝界面欺騙用戶行為.
所以開發(fā)者需要調(diào)整AndroidManifest文件里的權(quán)限,增加 REQUEST_INSTALL_PACKAGES權(quán)限.

<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

谷歌建議是通過PackageManager canRequestPackageInstalls() 的API案站,查詢此權(quán)限的狀態(tài),然后使用使用 ACTION_MANAGE_UNKNOWN_APP_SOURCES Intent 操作

  Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
                startActivityForResult(intent, RESULT_CODE);

但是筆者不建議這樣使用,因?yàn)槭褂?ACTION_MANAGE_UNKNOWN_APP_SOURCES Intent 操作后會跳到所有應(yīng)用列表,然后從眾多的應(yīng)用里選擇對應(yīng)的APP的選擇進(jìn)入再打開權(quán)限,這樣的用戶體驗(yàn)不好.

image.png

所以筆者建議不使用判斷和Intent跳轉(zhuǎn).而是直接使用Intent里帶apk的安裝,會有提示,然后直接進(jìn)入權(quán)限開關(guān)的界面,這樣的體驗(yàn)相對好,而發(fā)現(xiàn)其他的主流的APP安裝時也是這樣.

流程如下:

packageinstaller-InstallStart-06072018110113.png
packageinstaller-InstallStart-06072018110134.png

Android 7 如何安裝apk

這里談?wù)凙ndroid 7 安裝apk時有什么改變.

參考谷歌文檔 FileProvider , Setup-sharing

從文檔里知道,Android 7 開始增加安全性,文件私有化,而需要共享文件給其他程序,例如APK安裝程序,需要通過FileProvider配置共享文件,配置表是基于XML文件實(shí)現(xiàn),然后通過Content URI攜帶配置文件xml來共享文件.

實(shí)現(xiàn)配置FileProvider 需要兩步:
第一步: 需要配置AndroidManifest.xml清單.

<provider  
    android:name="android.support.v4.content.FileProvider"  
    android:authorities="${applicationId}.provider"  
    android:exported="false"  
    android:grantUriPermissions="true">  
    <!-- 元數(shù)據(jù) -->  
    <meta-data  
        android:name="android.support.FILE_PROVIDER_PATHS"  
        android:resource="@xml/file_paths" />  
</provider>

第二步:建立文件 res/xml/file_paths.xml.

<?xml version="1.0" encoding="utf-8"?>  
<resources>  
    <paths>  
        <!--  
        files-path:          該方式提供在應(yīng)用的內(nèi)部存儲區(qū)的文件/子目錄的文件。  
                              它對應(yīng)Context.getFilesDir返回的路徑:eg:”/data/data/com.***.***/files”。  
  
        cache-path:          該方式提供在應(yīng)用的內(nèi)部存儲區(qū)的緩存子目錄的文件伴嗡。  
                              它對應(yīng)Context.getCacheDir返回的路:eg:“/data/data/com.***.***/cache”锁蠕;  
  
        external-path:       該方式提供在外部存儲區(qū)域根目錄下的文件窍株。  
                              它對應(yīng)Environment.getExternalStorageDirectory返回的路徑

        external-files-path:  Context.getExternalFilesDir(null)

        external-cache-path: Context.getExternalCacheDir(String)
        -->  
        <external-path name="download" path="" />  
    </paths>  
</resources>

而其中的 path=""是代表根目錄,也就是向共享的應(yīng)用程序共享根目錄以及其子目錄的任何一個文件.理論上說假如共享程序是惡意程序,那它便可以獲取你的應(yīng)用的所有共享文件信息.

最后準(zhǔn)備好上面兩步便可以安裝文件

/**
  * android7.x
  * @param path 文件路徑
  */
  public void startInstallN(Context context, String path) {
      //參數(shù)1 上下文, 參數(shù)2 在AndroidManifest中的android:authorities值, 參數(shù)3  共享的文件  
      Uri apkUri = FileProvider.getUriForFile(context, Constants.AUTHORITY, new File(path));
      Intent install = new Intent(Intent.ACTION_VIEW);
      //由于沒有在Activity環(huán)境下啟動Activity,設(shè)置下面的標(biāo)簽 
      install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
      //添加這一句表示對目標(biāo)應(yīng)用臨時授權(quán)該Uri所代表的文件 
      install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
      install.setDataAndType(apkUri, "application/vnd.android.package-archive");
      startActivity(install);
  }

Android 6及以下版本 如何安裝apk

最后Android 6的安裝是簡單

/**
  *android1.x-6.x
  *@param path 文件的路徑
  */
public void startInstall(Context context, String path) {
        Intent install = new Intent(Intent.ACTION_VIEW);
        install.setDataAndType(Uri.parse("file://" + path), "application/vnd.android.package-archive");
        install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(install);
    }

最后

最后簡單總結(jié), 特別認(rèn)同 FitAndroid7 解決方法的理念.一行代碼解決一個基礎(chǔ)功能.

相關(guān)引用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末距芬,一起剝皮案震驚了整個濱河市悬槽,隨后出現(xiàn)的幾起案子悔常,更是在濱河造成了極大的恐慌影斑,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件机打,死亡現(xiàn)場離奇詭異矫户,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)残邀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門皆辽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來柑蛇,“玉大人,你說我怎么就攤上這事驱闷〕芴ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵空另,是天一觀的道長盆耽。 經(jīng)常有香客問我,道長扼菠,這世上最難降的妖魔是什么摄杂? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮循榆,結(jié)果婚禮上析恢,老公的妹妹穿的比我還像新娘。我一直安慰自己冯痢,他們只是感情好氮昧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著浦楣,像睡著了一般袖肥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上振劳,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天椎组,我揣著相機(jī)與錄音,去河邊找鬼历恐。 笑死寸癌,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的弱贼。 我是一名探鬼主播蒸苇,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼吮旅!你這毒婦竟也來了溪烤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤庇勃,失蹤者是張志新(化名)和其女友劉穎檬嘀,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體责嚷,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鸳兽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了罕拂。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片揍异。...
    茶點(diǎn)故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡全陨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蒿秦,到底是詐尸還是另有隱情烤镐,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布棍鳖,位于F島的核電站炮叶,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏渡处。R本人自食惡果不足惜镜悉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望医瘫。 院中可真熱鬧侣肄,春花似錦、人聲如沸醇份。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽僚纷。三九已至矩距,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間怖竭,已是汗流浹背锥债。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留痊臭,地道東北人哮肚。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像广匙,于是被迫代替她去往敵國和親允趟。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 很多開發(fā)者應(yīng)該都知道android7.0以上安裝apk的問題鸦致。但是看了一些文章潮剪,并沒有很好的幫助我解決問題。而且還...
    sys_out閱讀 1,652評論 0 3
  • 轉(zhuǎn)載自于連林 我們使用手機(jī)的時候經(jīng)常會看到應(yīng)用程序提示升級蹋凝,大部分應(yīng)用內(nèi)部都需要實(shí)現(xiàn)升級提醒和應(yīng)用程序文件(APK...
    sirai閱讀 1,147評論 0 24
  • 我們使用手機(jī)的時候經(jīng)常會看到應(yīng)用程序提示升級鲁纠,大部分應(yīng)用內(nèi)部都需要實(shí)現(xiàn)升級提醒和應(yīng)用程序文件(APK文件)下載总棵。 ...
    于連林520wcf閱讀 33,878評論 43 149
  • Android7.0下載Apk自動安裝 1. 整體需求 下載APK文件使用DownloadManager來下載在應(yīng)...
    陳豐堯閱讀 4,011評論 3 10
  • 問題描述: 最近在做一個項(xiàng)目情龄,要求當(dāng)前的app可以下載安裝另一個app迄汛,安裝apk的代碼如下: 但當(dāng)apk下載完之...
    玉圣閱讀 458評論 0 0