Android7.0反射类找不到的问题

Java中使用反射的地方较多,尤其是各种框架中。最近在Android7.0的项目中遇到个问题很奇怪,反射使用的类找不到了,但是编译的时候没问题啊。然后在代码中使用非反射的方式调用代码也是没有问题的,这时奇怪的现象出现了,加入手动调用代码后反射代码找不到类的问题也不出现了。其实这个是混淆代码所做的工作,一个类没有被使用的情况下会在编译中直接删除掉,显然并没有考虑反射调用的情况。关闭混淆或者修改混淆的配置文件即可解决这个问题。各种框架自动所做的工作大部分是节省了程序员的时间,但是一旦出问题查起来花费的时间也是不少

当处于应用层时,如果只是修改应用内多语言时,上层app可以轻松完成各种语言的切换,网上方法很多,就不在详细叙述,app内部设置多语言可参考下面这篇文章

Android 实现应用内置语言切换(附有源码下载地址7.0可用)。

但是,如何通过app,设置系统语言呢?这正是本文讨论核心。

android6.0

android设置系统语言的核心方法在framework层,地址是\frameworks\base\core\java\com\android\internal\app\LocalePicker.java类里,方法如下:

   /**
     * Requests the system to update the system locale. Note that the system looks halted
     * for a while during the Locale migration, so the caller need to take care of it.
     */
    public static void updateLocale(Locale locale) {
        try {
            IActivityManager am = ActivityManagerNative.getDefault();
            Configuration config = am.getConfiguration();
            config.setLocale(locale);
            config.userSetLocale = true;
            am.updateConfiguration(config);
            // Trigger the dirty bit for the Settings Provider.
            BackupManager.dataChanged("com.android.providers.settings");
        } catch (RemoteException e) {
            // Intentionally left blank
        }
    }

android6.0设置系统语言的关键逻辑就是上面那个方法。如果上层APP想要设置系统语言必须通过反射方法获取,核心方法代码如下(本方法可以持久化系统语言设置,也就是说重启手机后不会恢复默认系统语言):

private void changeSystemLanguage(Locale locale) {
    if (locale != null) {
        try {
            Class classActivityManagerNative = Class.forName("android.app.ActivityManagerNative");
            Method getDefault = classActivityManagerNative.getDeclaredMethod("getDefault");
            Object objIActivityManager = getDefault.invoke(classActivityManagerNative);
            Class classIActivityManager = Class.forName("android.app.IActivityManager");
            Method getConfiguration = classIActivityManager.getDeclaredMethod("getConfiguration");
            Configuration config = (Configuration) getConfiguration.invoke(objIActivityManager);
            config.setLocale(locale);
            //config.userSetLocale = true;
            Class clzConfig = Class
                    .forName("android.content.res.Configuration");
            java.lang.reflect.Field userSetLocale = clzConfig
                    .getField("userSetLocale");
            userSetLocale.set(config, true);
            Class[] clzParams = {Configuration.class};
            Method updateConfiguration = classIActivityManager.getDeclaredMethod("updateConfiguration", clzParams);
            updateConfiguration.invoke(objIActivityManager, config);
            BackupManager.dataChanged("com.android.providers.settings");
        } catch (Exception e) {
            Log.d(TAG, "changeSystemLanguage: " + e.getLocalizedMessage());
        }
    }
}
调用时如下:

Local locale = Locale.ENGLISH;
changeSystemLanguage(locale);
系统语言就变成了英文。(不再赘述)

android7.0

7.0与6.0的源码有所不同,LocalePicker.Java定义系统语言的方式,不在是一种Local,而是一个LocaleList,具体方法如下:

  public static void updateLocale(Locale locale) {
        updateLocales(new LocaleList(locale));
    }

updateLocale调用了updateLocales方法,updateLocales方法如下:

 public static void updateLocales(LocaleList locales) {
        try {
            final IActivityManager am = ActivityManagerNative.getDefault();
            final Configuration config = am.getConfiguration();
            config.setLocales(locales);
            config.userSetLocale = true;
            am.updatePersistentConfiguration(config);
            // Trigger the dirty bit for the Settings Provider.
            BackupManager.dataChanged("com.android.providers.settings");
        } catch (RemoteException e) {
            // Intentionally left blank
        }
    }

可见,6.0上的反射直接照搬到7.0是不起作用的,需要重新运用反射方法,反射方法代码如下

protected void changeSystemLanguage(LocaleList locale) {
    if (locale != null) {
        try {
            Class classActivityManagerNative = Class.forName("android.app.ActivityManagerNative");
            Method getDefault = classActivityManagerNative.getDeclaredMethod("getDefault");
            Object objIActivityManager = getDefault.invoke(classActivityManagerNative);
            Class classIActivityManager = Class.forName("android.app.IActivityManager");
            Method getConfiguration = classIActivityManager.getDeclaredMethod("getConfiguration");
            Configuration config = (Configuration) getConfiguration.invoke(objIActivityManager);
            config.setLocales(locale);
            Class[] clzParams = {Configuration.class};
            Method updateConfiguration = classIActivityManager.getDeclaredMethod("updatePersistentConfiguration", clzParams);
            updateConfiguration.invoke(objIActivityManager, config);
        } catch (Exception e) {
            Log.d(TAG, "changeSystemLanguage: " + e.getLocalizedMessage());
        }
    }
}

6.0和7.0设置系统语言源码不同之出,有两点:

1.设置参数的方法不同,6.0是updateConfiguration,7.0是updatePersistentConfiguration,这点需要注意

2.6.0传递的local,而7.0是一个列表LocaleList

7.0反射方法调用如下:

Locale newLocale = new Locale("zh", "CN");
final LocaleList localeList = new LocaleList(newLocale);
changeSystemLanguage(localeList);

android7.0app切换系统语言Demo源码下载:http://download.csdn.net/download/zhaokai621/9930068


生成的apk,需要系统签名,可放在源码vendor\customer\你的文件下通过mm编译,需要注意的是,需要有.mk文件,生成的apk在out的目录下(当然层级有很多),把out目录下生成的apkpush到手机system/priv-app/你的文件夹,重启手机即可。

操作如下:

1.把studio生成的apk放入如下目录:


Android.mk文件如下(供参考):

--------------------------开始(下面才是)-------------------------------------------------------------

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Module name should match apk name to be installed
LOCAL_MODULE := Test
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_MODULE_CLASS := APPS
LOCAL_OVERRIDES_PACKAGES := Calendar
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := platform
#LOCAL_PREBUILT_JNI_LIBS:= \
#@lib/armeabi/liblocSDK4d.so
#LOCAL_MODULE_PATH := $(TARGET_OUT)/vendor/operator/app
LOCAL_PRIVILEGED_MODULE := true
include $(BUILD_PREBUILT)

--------------------------------结束(本行不是)-----------------------------------------------------------------------------

2.编译源码,单编模块

命令如下(前提是你已经整编过一套android源码)

source ./build/envsetup.sh(加载命令)

lunch 16(序号和你整编时选的一样,本文以android7.0源码为准)

mmm vendor/customer/Test

3.生成的apk(已经打包了系统签名):在如下目录(可能有出入)


4.push到手机,不要install,重启手机

adb push XXXX system/priv-app/Test

XXX是你out生成的apk,可拖拽到此。


现在就可以看到一个应用了,点击就可以切换系统语言了。多多交流   *-*


android7.0app切换系统语言Demo源码下载:http://download.csdn.net/download/zhaokai621/9930068

你可能感兴趣的:(Android7.0反射类找不到的问题)