[MTK项目] 如何客制化谷歌开机向导

本文介绍如何在没有源码的情况下,使用RuntimeResourceOverlay (RRO) 定制谷歌开机向导(SUW),包括修改wizard_script文件以添加自定义页面,及实现页面跳转。

最近项目中有个任务,要在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。就可以看到我们定制开机向导页面了。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值