android以欺骗的方法使用隐藏API调用举例(国际化,多语言)

news/2024/7/6 5:08:35


Android对国际化与多语言切换已经做得不错了,一个应用只要命名相应语系的values-[language]文件夹,通过“设置”→“语言&键盘”→“选择语言”即可实现应用多种语言的切换。   
    但如何在应用里自己实现?搜索过发现网上有如下的做法:
  1.          Resources res = getResources();
  2.          Configuration config = res.getConfiguration();
  3.          config.locale = locale;
  4.          DisplayMetrics dm = res.getDisplayMetrics();
  5.          res.updateConfiguration(config, dm);
复制代码
亲测,不成功。好吧,程序员又到了自力更生的时候了。下面开始讲应用多语言切换的三种方法。
    
    先上效果图:

前两种方法的原理即在应用里实现“选择语言”。通过查看源码,其核心代码为:
  1.                 IActivityManager iActMag = ActivityManagerNative.getDefault();
  2.                 try {
  3.                         Configuration config = iActMag.getConfiguration();
  4.                         config.locale = locale;
  5.                         // 此处需要声明权限:android.permission.CHANGE_CONFIGURATION
  6.                         // 会重新调用 onCreate();
  7.                         iActMag.updateConfiguration(config);
  8.                 } catch (RemoteException e) {
  9.                         e.printStackTrace();
  10.                 }
  11.                 PS:感谢 曾阳 的帮助。
复制代码
可以发现IActivityManager与ActivityManagerNative都是非公开类。如何调用?第一种是API欺骗,第二种是使用Java反射机制。
    1. API欺骗
    烧制到手机中的android.jar包含了Android所需的各种类与方法;而供开发者使用的android.jar只是其中的一部分。API欺骗是指在应用中去模拟未公开的类和方法让应用编译通过并生成APK,然而在应用实际运行中调用的却仍是烧制到手机中真实的android.jar。
    
    通过核心代码可以看到我们要模拟的是ActivityManagerNative中的一个方法getDefault()和IActivityManager中的两个方法getConfiguration()与updateConfiguration(config)。参照源码,应用的工程结构图及代码模拟如下:
    
    工程结构图:

代码:
  1. ActivityManagerNative.java
  2. package android.app;

  3. /**
  4. * @author Sodino E-mail:sodinoopen@hotmail.com
  5. * @version Time:2011-7-10 上午11:37:01
  6. */
  7. public abstract class ActivityManagerNative {
  8.         public static IActivityManager getDefault() {
  9.                 return null;
  10.         }
  11. }

  12. IActivityManager.java
  13. package android.app;

  14. import android.content.res.Configuration;
  15. import android.os.RemoteException;

  16. /**
  17. * @author Sodino E-mail:sodinoopen@hotmail.com
  18. * @version Time:2011-7-10 上午11:37:46
  19. */
  20. public abstract interface IActivityManager {
  21.         public abstract Configuration getConfiguration() throws RemoteException;

  22.         public abstract void updateConfiguration(Configuration paramConfiguration)
  23.                         throws RemoteException;
  24. }
复制代码
实现模拟了这两个类后,即可正常使用上面提到的转换语系的核心代码了。

    2. Java反射机制
    不多说了,Java反射机制入门教程:
    http://java.sun.com/developer/te ... flection/index.html
    之前写过的几个使用Java反射的例子:
    [Android]获取未安装的APK图标(原创非转帖)
    http://blog.csdn.net/sodino/article/details/6215224
    [Android]挂断、接听电话
    http://blog.csdn.net/sodino/article/details/6181610
    
    直接上代码:
  1.         private void updateLanguage(Locale locale) {
  2.                 Log.d("ANDROID_LAB", locale.toString());
  3.                 try {
  4.                         Object objIActMag, objActMagNative;
  5.                         Class clzIActMag = Class.forName("android.app.IActivityManager");
  6.                         Class clzActMagNative = Class.forName("android.app.ActivityManagerNative");
  7.                         Method mtdActMagNative$getDefault = clzActMagNative.getDeclaredMethod("getDefault");
  8.                         // IActivityManager iActMag = ActivityManagerNative.getDefault();
  9.                         objIActMag = mtdActMagNative$getDefault.invoke(clzActMagNative);
  10.                         // Configuration config = iActMag.getConfiguration();
  11.                         Method mtdIActMag$getConfiguration = clzIActMag.getDeclaredMethod("getConfiguration");
  12.                         Configuration config = (Configuration) mtdIActMag$getConfiguration.invoke(objIActMag);
  13.                         config.locale = locale;
  14.                         // iActMag.updateConfiguration(config);
  15.                         // 此处需要声明权限:android.permission.CHANGE_CONFIGURATION
  16.                         // 会重新调用 onCreate();
  17.                         Class[] clzParams = { Configuration.class };
  18.                         Method mtdIActMag$updateConfiguration = clzIActMag.getDeclaredMethod(
  19.                                         "updateConfiguration", clzParams);
  20.                         mtdIActMag$updateConfiguration.invoke(objIActMag, config);
  21.                 } catch (Exception e) {
  22.                         e.printStackTrace();
  23.                 }
  24.         }
复制代码
实际运行后,发现对当前系统设置了新的Locale后,不单自己的应用语系改变了,系统所有的应用语系都改变了。这肯定是不合理的。有一个解决办法是在应用界面退出前再次对系统设置成碑的Locale,不过个人不喜欢这样的办法,加之调用updateConfiguration()方法后,整个Activity会重新onCreate(),这个考虑Activity的生命周期可有点费劲了。于是有了下面这第三种方法。
    
    3. 自己转换语系(哈哈,这个名字很现实啊)
    动手实现嘛,啥都系统弄好了,那程序员的存在还有什么意义呢。
    自己转换语系有点麻烦,先看工程结构图:

values/strings.xml与xml/english.xml的内容是相同的;values-zh-rCN/strings.xml与xml/chinese.xml的内容也是相同的。出现这样的冗余是因为生成APK时values下的内容都打到rasc去了,读取不了了。
    
    自己实现语系的转换需要考虑到:
    3.1  R.xxxxx.id与对应语系中文本串的对应(需要特别考虑到R.array.string字符串数组)。
    3.2 解析xml。
    3.3 设置语系后,所有界面元素的手动刷新。
    
    在xml中声明一个string是这个的格式:
  1.     语言应用
复制代码
对应R文件会生成一个id指代该string
  1.     public static final class string {
  2.         public static final int app_name=0x7f050001;
  3.     }
复制代码
3.1的问题就是如何实现id与string的匹配,解决方法为:
  1.         Resources res = context.getResources();
  2.         String pkg = context.getPackageName();
  3.         String tag = "app_name";
  4.         int idTag = res.getIdentifier(tag, "string", pkg);
复制代码

3.2 解析XML
    这儿要用到一个新的工具了:XmlResourceParser,解析过程有点绕,但比SAX简单些。具体细节见LanguageApp_Sodino工程中的代码吧。
    3.3 手动刷新界面。
    要获取所有涉及到语系更新组件的索引逐一更新,体力活儿,细心点花点力气也可实现。
    
    详细实现过程见下面三个工程中:

(PS:不要问我为什么下载的工程在IDE中为什么无法直接使用,为什么打开是乱码红叉一大堆,既然是程序员,遇到问题是不是也该自己多思考思考呢。)

转载于http://www.devdiv.com/article-2274-1.html

Android对国际化与多语言切换已经做得不错了,一个应用只要命名相应语系的values-[language]文件夹,通过“设置”→“语言&键盘”→“选择语言”即可实现应用多种语言的切换。   
    但如何在应用里自己实现?搜索过发现网上有如下的做法:
  1.          Resources res = getResources();
  2.          Configuration config = res.getConfiguration();
  3.          config.locale = locale;
  4.          DisplayMetrics dm = res.getDisplayMetrics();
  5.          res.updateConfiguration(config, dm);
复制代码
亲测,不成功。好吧,程序员又到了自力更生的时候了。下面开始讲应用多语言切换的三种方法。
    
    先上效果图:

前两种方法的原理即在应用里实现“选择语言”。通过查看源码,其核心代码为:
  1.                 IActivityManager iActMag = ActivityManagerNative.getDefault();
  2.                 try {
  3.                         Configuration config = iActMag.getConfiguration();
  4.                         config.locale = locale;
  5.                         // 此处需要声明权限:android.permission.CHANGE_CONFIGURATION
  6.                         // 会重新调用 onCreate();
  7.                         iActMag.updateConfiguration(config);
  8.                 } catch (RemoteException e) {
  9.                         e.printStackTrace();
  10.                 }
  11.                 PS:感谢 曾阳 的帮助。
复制代码
可以发现IActivityManager与ActivityManagerNative都是非公开类。如何调用?第一种是API欺骗,第二种是使用Java反射机制。
    1. API欺骗
    烧制到手机中的android.jar包含了Android所需的各种类与方法;而供开发者使用的android.jar只是其中的一部分。API欺骗是指在应用中去模拟未公开的类和方法让应用编译通过并生成APK,然而在应用实际运行中调用的却仍是烧制到手机中真实的android.jar。
    
    通过核心代码可以看到我们要模拟的是ActivityManagerNative中的一个方法getDefault()和IActivityManager中的两个方法getConfiguration()与updateConfiguration(config)。参照源码,应用的工程结构图及代码模拟如下:
    
    工程结构图:

代码:
  1. ActivityManagerNative.java
  2. package android.app;

  3. /**
  4. * @author Sodino E-mail:sodinoopen@hotmail.com
  5. * @version Time:2011-7-10 上午11:37:01
  6. */
  7. public abstract class ActivityManagerNative {
  8.         public static IActivityManager getDefault() {
  9.                 return null;
  10.         }
  11. }

  12. IActivityManager.java
  13. package android.app;

  14. import android.content.res.Configuration;
  15. import android.os.RemoteException;

  16. /**
  17. * @author Sodino E-mail:sodinoopen@hotmail.com
  18. * @version Time:2011-7-10 上午11:37:46
  19. */
  20. public abstract interface IActivityManager {
  21.         public abstract Configuration getConfiguration() throws RemoteException;

  22.         public abstract void updateConfiguration(Configuration paramConfiguration)
  23.                         throws RemoteException;
  24. }
复制代码
实现模拟了这两个类后,即可正常使用上面提到的转换语系的核心代码了。

    2. Java反射机制
    不多说了,Java反射机制入门教程:
    http://java.sun.com/developer/te ... flection/index.html
    之前写过的几个使用Java反射的例子:
    [Android]获取未安装的APK图标(原创非转帖)
    http://blog.csdn.net/sodino/article/details/6215224
    [Android]挂断、接听电话
    http://blog.csdn.net/sodino/article/details/6181610
    
    直接上代码:
  1.         private void updateLanguage(Locale locale) {
  2.                 Log.d("ANDROID_LAB", locale.toString());
  3.                 try {
  4.                         Object objIActMag, objActMagNative;
  5.                         Class clzIActMag = Class.forName("android.app.IActivityManager");
  6.                         Class clzActMagNative = Class.forName("android.app.ActivityManagerNative");
  7.                         Method mtdActMagNative$getDefault = clzActMagNative.getDeclaredMethod("getDefault");
  8.                         // IActivityManager iActMag = ActivityManagerNative.getDefault();
  9.                         objIActMag = mtdActMagNative$getDefault.invoke(clzActMagNative);
  10.                         // Configuration config = iActMag.getConfiguration();
  11.                         Method mtdIActMag$getConfiguration = clzIActMag.getDeclaredMethod("getConfiguration");
  12.                         Configuration config = (Configuration) mtdIActMag$getConfiguration.invoke(objIActMag);
  13.                         config.locale = locale;
  14.                         // iActMag.updateConfiguration(config);
  15.                         // 此处需要声明权限:android.permission.CHANGE_CONFIGURATION
  16.                         // 会重新调用 onCreate();
  17.                         Class[] clzParams = { Configuration.class };
  18.                         Method mtdIActMag$updateConfiguration = clzIActMag.getDeclaredMethod(
  19.                                         "updateConfiguration", clzParams);
  20.                         mtdIActMag$updateConfiguration.invoke(objIActMag, config);
  21.                 } catch (Exception e) {
  22.                         e.printStackTrace();
  23.                 }
  24.         }
复制代码
实际运行后,发现对当前系统设置了新的Locale后,不单自己的应用语系改变了,系统所有的应用语系都改变了。这肯定是不合理的。有一个解决办法是在应用界面退出前再次对系统设置成碑的Locale,不过个人不喜欢这样的办法,加之调用updateConfiguration()方法后,整个Activity会重新onCreate(),这个考虑Activity的生命周期可有点费劲了。于是有了下面这第三种方法。
    
    3. 自己转换语系(哈哈,这个名字很现实啊)
    动手实现嘛,啥都系统弄好了,那程序员的存在还有什么意义呢。
    自己转换语系有点麻烦,先看工程结构图:

values/strings.xml与xml/english.xml的内容是相同的;values-zh-rCN/strings.xml与xml/chinese.xml的内容也是相同的。出现这样的冗余是因为生成APK时values下的内容都打到rasc去了,读取不了了。
    
    自己实现语系的转换需要考虑到:
    3.1  R.xxxxx.id与对应语系中文本串的对应(需要特别考虑到R.array.string字符串数组)。
    3.2 解析xml。
    3.3 设置语系后,所有界面元素的手动刷新。
    
    在xml中声明一个string是这个的格式:
  1.     语言应用
复制代码
对应R文件会生成一个id指代该string
  1.     public static final class string {
  2.         public static final int app_name=0x7f050001;
  3.     }
复制代码
3.1的问题就是如何实现id与string的匹配,解决方法为:
  1.         Resources res = context.getResources();
  2.         String pkg = context.getPackageName();
  3.         String tag = "app_name";
  4.         int idTag = res.getIdentifier(tag, "string", pkg);
复制代码

3.2 解析XML
    这儿要用到一个新的工具了:XmlResourceParser,解析过程有点绕,但比SAX简单些。具体细节见LanguageApp_Sodino工程中的代码吧。
    3.3 手动刷新界面。
    要获取所有涉及到语系更新组件的索引逐一更新,体力活儿,细心点花点力气也可实现。
    
    详细实现过程见下面三个工程中:

(PS:不要问我为什么下载的工程在IDE中为什么无法直接使用,为什么打开是乱码红叉一大堆,既然是程序员,遇到问题是不是也该自己多思考思考呢。)

转载于http://www.devdiv.com/article-2274-1.html


http://www.niftyadmin.cn/n/3649238.html

相关文章

[收藏]mvm的“公司如船”大论

mvm的:http://home.wangjianshuo.com/mvm/000525.htm公司如船有个企业家被问到他为什么喜欢航海。他的回答是,航海和经营企业有强烈的共同点:到了海上以后,就算船上有人你不喜欢,你也只能去适应他,而不可能…

关于公司系统支撑工作的建议

关于公司系统支撑工作的建议成晓旭刚来部门不久,对部门的整体工作情况了解不多,对公司的信息系统建设情况更是不敢枉自品评。对于像我们这样规模的公司,自己建设、实施和维护满足公司自身管理要求的管理信息系统,是目前部门公司对…

如何将class文件打包成jar文件

如何将class文件打包成jar文件,这是一个很严肃的问题,当你在在使用webservice的saop协议的时候,很多地方不免需要用到远程jar包,这些jar包里面,存放的将是你的VO或者是JavaBean 这些方法都将对外提供并暴露。好了 &…

vue密码正则验证表单验证_如何在Vue中使用表单验证

vue密码正则验证表单验证介绍 (Introduction) Almost every web application makes use of forms in some way, as such developers always have to tackle form validations. If you are a new developer, it can be hard deciding how best to approach this. Depending on t…

使用SharedStore的Python实现方法

打算在我的QTP framework中的HTML reporting里面加入detailed steps,想到了早期翻译的Tarun的文章中提到的一个工具:Shared Store 由于是COM组件,所以可以在python中实现 (我的HTML reporting也是用python实现的) 以…

[收藏]wuvist经典讲解MSNMessenger的四个联系人列表

原文:http://www.blogwind.com/wuvist/comment.aspx?article_id7004MSN其实有四个列表:ForwardList,AllowedList,ReverseList,跟BlockedList。我们平时看到的联系人列表其实只是:ForwardList而已。当我们看…

Ubuntu 11 安装Subversion成功记

综合了几个网页信息,结合自己的理解,在Ubuntu11上搭建成功了svn server 第一步:安装apache2 libapache2-svn subversion sudo apt-get install apache2 sudo apt-get install subversion sudo apt-get install libapache2-svn安装完后按照…

gatsby_Gatsby更快的WordPress网站

gatsbyTalk about the latest cutting-edge web technologies, and you find some impressive names like React.js, Vue.js, Next.js, and so on. They have opened new gateways and approaches to building websites that can serve content to users quickly. 谈论最新的前…