最近项目中有个任务,要在gms中的谷歌开机向导(SUW,SetupWizard)中加入客制化页面。之前没有做过相关的东西,第一反应这是不行的,因为gms包的谷歌软件我们都没有源码,不能做任何修改。接到任务后先做预研,上网查了资料发现谷歌开机向导虽然没有源码,但是却真的可以客制化,可以删减某些页面,也可以插入自己开发的页面。谷歌为定制gms开机向导也提供了一套定制化的方法。这里先为大家介绍下定制谷歌开机向导的方法。
没有源码,如何修改apk?
答案是---Runtime Resource Overlay(RRO,运行时资源替换)。RRO是在Android5.0后引入的,它能在 apk 运行时,自动加载需要定制的资源,而不加载原有的资源。RRO机制的运用是依靠overlay apk实现的,overlay apk是一个独立的apk,可以没有代码,但必须包括想要替换的资源文件,且资源文件名要与目标apk的资源文件相同。
实际上,RRO能支持除了layout和AndroidManifest 外的所有资源定制,比如string、drawable等,在做ROM定制开发时还是非常有用的。至于PRO的使用细节,这里不做详细介绍,有兴趣的同学可以去网上搜索具体的使用方法。我们只要知道这个机制可以帮助我们在没有源码的情况下修改apk就行了。
RRO定制谷歌开机向导
RRO机制只能替换资源文件,我们定制SUW也是替换相关的资源文件实现的。在SUW中,有一个wizard_script资源文件,这个文件定义了SUW的页面跳转行为。要追加页面就需要更改 wizard_script 文件内容。此文件内容如下:
<WizardAction
id="welcome"
wizard:uri="intent:#Intent;action=com.android.setupwizard.WELCOME;end" >
<result wizard:action="sim_setup" />
</WizardAction>
<WizardAction
id="sim_setup"
wizard:uri="intent:#Intent;action=com.android.setup.SIM_SETUP;end" >
<result wizard:action="wifi_settings" />
</WizardAction>
<!-- Wi-Fi setup -->
<WizardAction id="wifi_settings"
wizard:uri="intent:#Intent;action=com.android.setupwizard.WIFI_SETTINGS;end">
<result wizard:action="connection_check" />
</WizardAction>
每一个WizardAction节点对应的就是SUW里面的一个页面,其中uri代表当前action可以处理的intent, id表示当前action,result代表点当前action跳转的目的action。上面的代码只是wizard_script文件的一部分,我们可以看到id为welcome的WizardAction其实就是开机向导的欢迎界面(选择语音),它的下一步是id为sim_setup的WizardAction,对应的是 sim卡设置界面。sim_setup的下一步是wifi_settings,也就是Wifi设置界面。这其中wizard:uri对应的就是调起当前页面的Intent。我们通过RRO机制,替换掉原始SUW里面的wizard_script,从而使wizard_script能调用到我们在源码里添加的的intent,就能调起我们自己的页面,从而实现SUW的定制需求。
制作一个overlay apk
1.源码中添加一个apk工程,放在package/app下,取名SetupWizardExt。
android.mk文件如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
include $(BUILD_MULTI_PREBUILT)
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := SetupWizardExt
LOCAL_CERTIFICATE := shared
LOCAL_PRIVILEGED_MODULE := true
LOCAL_MODULE_TAGS := optional
LOCAL_OVERRIDES_PACKAGES := provision Setup
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_SRC_FILES := $(call all-java-files-under, src/com/wingtech/setup)
#apk包名com.wingtech.setup
include $(BUILD_PACKAGE)
include $(call all-makefiles-under,$(LOCAL_PATH))
2.将此工程加入到源码编译环境中
这个方法很多,我是加在了build/target/product/core.mk的PRODUCT_PACKAGES变量中。
3.修改wizard_script.xml
我们在SUW的语音选择界面后添加自己的页面,增加一个WizardAction,id 为wingtech_welcome,启动此页面的Intent的action为“com.wingtech.setup.WELCOME”。
<WizardAction
id="welcome"
wizard:uri="intent:#Intent;action=com.android.setupwizard.WELCOME;end" >
<result wizard:action="wingtech_welcome" />
</WizardAction>
<WizardAction
id="wingtech_welcome"
wizard:uri="intent:#Intent;action=com.wingtech.setup.WELCOME;end" >
<result wizard:action="sim_setup" />
</WizardAction>
<WizardAction
id="sim_setup"
wizard:uri="intent:#Intent;action=com.android.setup.SIM_SETUP;end" >
<result wizard:action="wifi_settings" />
</WizardAction>
将wizard_script.xml一定要放在工程资源目录下的raw文件夹中,也是就res/raw/wizard_script.xml,因为SUW的wizard_script.xml也在这个目录下,必须保持一致。
4.定义一个com.wingtech.setup.HomeActivity,接收wizard_script中定义的Intent。
在manefest中声明:
<activity
android:name=".HomeActivity"
android:configChanges="keyboardHidden|orientation|screenSize|locale|layoutDirection"
android:excludeFromRecents="true"
android:immersive="true"
android:launchMode="singleTask" >
<intent-filter>
<action android:name="com.wingtech.setup.WELCOME" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
至于HomeActivity的Java文件的具体写法跟其他普通Activity完全一样,只是要在声明的时候接收"com.wingtech.setup.WELCOME"的intent。
5.工程中添加PARTNER_CUSTOMIZATION的广播接收器
定义SetupReceiver,并接收"com.android.setupwizard.action.PARTNER_CUSTOMIZATION"广播,这个广播是谷歌规定的,必须接收,这是最关键的一步,如果不接收此广播,我们的RRO机制是不会生效的,一定要添加。
在manefest中声明:
<receiver
android:name=".SetupReceiver"
android:exported="false" >
<intent-filter>
<action android:name="android.intent.action.PRE_BOOT_COMPLETED" />
<action android:name="com.android.setupwizard.action.PARTNER_CUSTOMIZATION" />
</intent-filter>
</receiver>
Java代码如下,没有实现任何具体功能,但必须要有声明:
public class SetupReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, final Intent intent) {
}
}
也可根据需求在Receiver接收其他intent,完成其他功能,不影响我们RRO机制。
6.处理自定义页面跳转
添加自定义页面后,还要能跳转到下一页。处理也很简单,因为我们在wizard_script.xml中定义页面对应的WizardAction的时候已经指明了下一步页面的id:
<WizardAction
id="wingtech_welcome"
wizard:uri="intent:#Intent;action=com.wingtech.setup.WELCOME;end" >
<result wizard:action="sim_setup" />
</WizardAction>
通过google预定义好的字段名称,我们可以获取到下个页面的id,并实现跳转。这里把跳转逻辑封装成了一个工具类:
public class SetupUtility {
private static final String EXTRA_THEME = "theme";
// Google Wizard Manager Constants
private static final String ACTION_NEXT = "com.android.wizard.NEXT";
private static final String EXTRA_ACTION_ID = "actionId";
private static final String EXTRA_SCRIPT_URI = "scriptUri";
private static final String EXTRA_RESULT_CODE = "com.android.setupwizard.ResultCode";
// GoogleSetupWizard
private static final String GOOGLE_SETUP_PACKAGE = "com.google.android.setupwizard";
private static final String GOOGLE_SETUP_HOME = "com.google.android.setupwizard.SetupWizardActivity";
public static void onNext(Intent intent, Activity activity, int resultCode) {
Intent nextIntent = new Intent(ACTION_NEXT);
nextIntent.putExtra(EXTRA_SCRIPT_URI, intent.getStringExtra(EXTRA_SCRIPT_URI));
nextIntent.putExtra(EXTRA_ACTION_ID, intent.getStringExtra(EXTRA_ACTION_ID));
nextIntent.putExtra(EXTRA_THEME, intent.getStringExtra(EXTRA_THEME));
nextIntent.putExtra(EXTRA_RESULT_CODE, resultCode);
activity.startActivityForResult(nextIntent, 10000); //Request Code doesn't really matter
}
}
红色字段都是google定义好的字段名称,这些都是固定的,不能修改,在自定义页面的Activity的getIntent()中获取字段,然后调用SetupUtility.onNext即可,
代码如下:
public void onClick(View v) {
switch (v.getId()) {
case R.id.button_back:
finish();
break;
case R.id.button_next:
SetupUtility.onNext(getIntent(), this, Activity.RESULT_OK);
break;
}
}
7.编译,烧写rom。就可以看到我们定制开机向导页面了。
[MTK项目] 如何客制化谷歌开机向导
最新推荐文章于 2024-06-24 10:59:41 发布
