最近剛找到工作,是手機方案公司,剛接觸手機系統預裝的APP,以及解決方案MTK平台下預裝APP的bug,也接觸到了Launcher的東西。
然后接觸到了第一個需求
PAI預裝APK功能
下面是我用到的帖子,也很感謝第一個博客主人,加了他QQ,問了很多東西
https://blog.csdn.net/xct841990555/article/details/80896429#commentsedit
這個帖子可能配置方面更加詳細
http://wossoneri.github.io/2017/06/19/[Android][Framework]PlayAutoInstall/?tdsourcetag=s_pcqq_aiomsg
什么是PAI
PAI(PlayAutoInstall)是一個自動下載安裝APK到手機,並且擺放在Launcher對應位置的一個機制。
因為國內沒有大湄公河次區域,所以很多人沒接觸過這個機制。這個機制其實對於運營商定制來說非常重要,比如美國的運營商,一個運營商有很多地區很多種類的SIM卡,當插上不同地區的SIM卡,運營商定制的手機就會下載不同的APP擺放在界面不同的位置。
其實主要是要兩個APK,一個預裝進的Android系統中(stub.apk),一個上傳到谷歌的合作伙伴服務器網站上(配置),然后在合作伙伴上進行一些配置就OK了。下面具體介紹這兩個APK的制作。
PAI流程
本地編譯一個PlayAutoInstallConfig.apk,簽名上傳到APFE服務器,APFE會驗證配置信息,並提供給Play商店中。當目標設備第一次開機啟動並且聯網(現在不必要登錄谷歌帳號),這些應用就會加入下載隊列,自動下載到手機。
配置菜單
先聊一下APFE會驗證的配置信息。
需要的配置信息包括:
- 指紋(必須)
- 城市(可選)
- 運營商(可選)
- 需要下載的應用程序列表
- 應用在桌面的位置信息
后兩項是編譯在PlayAutoInstallConfig.apk中的,前三項是把APK上傳到服務器時需要填寫的。
上傳服務器配置頁面如下:
配置信息的前三項匹配項如果填寫,就必須要完全匹配才能應用到手機。我遇到一個問題是配置上傳后PlayAutoInstallConfig.apk會在設定精靈過程中下載到手機,但需要Play商店中下載的應用怎么都不下載。后來發現是在上傳APK到服務器時運營商填的不對,導致無法下載。因為嘗試填寫幾種運營商名稱都不能正常工作,最后解決方案是只匹配指紋,不匹配城市和運營商(減少過濾項),這樣手機就可以和Play商店中信息匹配,然后就可以自動下載了。
關於其余配置,參考下面表格:
下面具體放代碼:分為2個APK,一個是預裝手機的APK(stub.apk)一個是放到服務器的APK(config.apk)
stub.apk
手機內必須要先預置一個符合下列條件的stub APK:
- 為一個系列的設備設置唯一的包名,包名格式為android.autoinstalls.config ..
- 必須配置一個接收器“android.autoinstalls.config.action.PLAY_AUTO_INSTALL”,並且設置export for flase
- 在預置的應用程序里只能有一個定義這個接收機
- 的versionCode必須定義成1
- APK必須預置在/ system / app(不能定義成特權,即不能放/ priv-app)
- 必須用私有密鑰簽名(汞用的TCL簽名)
- 不能定義權限/活動/其他接收者/內容提供者/服務
MK文件的代碼
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := LavaPAIStub
LOCAL_CERTIFICATE := platform
LOCAL_SDK_VERSION := current
LOCAL_AAPT_FLAGS := -x
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)
LOCAL_EXPORT_PACKAGE_RESOURCES := true LOCAL_MODULE_PATH := $(TARGET_OUT_APPS) include $(BUILD_PACKAGE)
AndroidManifest.xml中
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.autoinstalls.config.lava.A5s" android:versionCode="1" android:versionName="1">//versionCode和versionName一定要一樣,並且為1 //后面不變 <application android:allowBackup="false" android:label="@string/app_name" > <receiver android:name="DummyReceiver" android:exported="false" > <intent-filter> <action android:name="android.autoinstalls.config.action.PLAY_AUTO_INSTALL" /> </intent-filter> </receiver> </application> </manifest>
config.apk
這個APK是我們真正配置的APK。
它和前面的APK的關系是:包名一致因為PAI機制需要本地存在一個這個包名的APK,在開機的設定精靈階段,(如果聯網)它會從服務器下載這個寫有對應配置的APK到手機上,替換掉那個Stub APK。
關於PAIconfig APK的配置:
- 上傳的APK(也就是我們編出來的APK)包名與指紋要和存根一致
- APK簽名要一致
- 和存根配置同樣的接收器
- 的versionCode必須大於1000
- APK必須包含啟動布局配置的XML文件(即后面會提到的default_layout),不然上傳會失敗,因為上傳前會檢查這個XML文件,然后會把要下載的應用程序顯示出來。所以也必須要求至少定義一個需要下載的app。最多50個,建議放10~15個。(文檔還要求autoinstall的應用必須在launcher上指定擺放位置,目前看來是不需要的,有可能bb launcher做了修改)
- 界面會有文件夾,文件夾名稱字符串在APK本地資源定義,支持國際化。
- 需要自動下載的APK對設備來講必須是在Play商店中發布的,並且對該地區用戶可見
- 不能定義權限/活動/其他接收者/內容提供者/服務
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := LavaPAIConfig
LOCAL_CERTIFICATE := platform
LOCAL_SDK_VERSION := current
LOCAL_AAPT_FLAGS := -x
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)
LOCAL_EXPORT_PACKAGE_RESOURCES := true LOCAL_MODULE_PATH := $(TARGET_OUT_APPS) include $(BUILD_PACKAGE)
AndroidManifest.xml中
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.autoinstalls.config.lava.A5s" android:versionCode="1001" android:versionName="1001"> <application android:allowBackup="false" android:label="@string/app_name" > <receiver android:name="DummyReceiver" android:exported="false" > <intent-filter> <action android:name="android.autoinstalls.config.action.PLAY_AUTO_INSTALL" /> </intent-filter> </receiver> </application> </manifest>
default_layout.xml
//選擇要安裝的apk,把他們的包名拿到,然后在這個文件中配置
<?xml version="1.0" encoding="utf-8"?> <workspace> <autoinstall packageName="com.twitter.android" className="com.twitter.android.StartActivity" screen="1" x="0" y="0" groupid="0" requiredPreload="true" installByDefault="true" /> <autoinstall packageName="com.instagram.android" className="com.instagram.android.activity.MainTabActivity" screen="1" x="1" y="0" groupid="1" requiredPreload="true" installByDefault="true" /> <autoinstall packageName="com.whatsapp" className="com.whatsapp.Main" screen="1" x="2" y="0" groupid="1" requiredPreload="true" installByDefault="true" /> </workspace>
auto.install.xml
<install> <!-- Group Index Mapping --> <autoinstallgrouplist> <installgroup groupId="0" type="GOOGLE" /> <installgroup groupId="1" type="OEM" /> </autoinstallgrouplist> </install>
將配置上傳到服務器
下面我將代碼上傳到CSDN
猶豫我是系統預置,所以我是MK文件編譯。沒有Gradle,如果你們 要用gradle編譯,只需要把我的AndroidManifess.xml + res 這2個文件夾考入到你的項目
config + stub 里面都沒有 JAVA類
https://download.csdn.net/download/yangbin0513/10845496
驗證流程
用一台新手機,插入對應的SIM卡,你在服務器段,配置好,對應的運營商,然后把APK燒錄到系統里面,恢復出廠設置,重新開始,在過程中聯網,登錄谷歌帳號,進入后在引導功能的時候,會出現,你點選擇安裝,它就開始下載了,等到進入啟動界面,啟動器就會加載這個APK,