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

转载 2015年11月20日 10:25:28


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

相关文章推荐

通过api欺骗获取安卓应用的启动时间

原文地址:http://m.blog.csdn.net/blog/yutou58nian/21176139 Android平台上,一个App的启动时间可以说是一个重要的性能指标。如何获取...

android程序内多语言切换不需要重新启动的解决方案

关于android程序内的的多语言切换,一般能搜索到这段代码: public void switchLanguage(Locale locale) { Conf...

Android 切换系统语言功能实现(下)

转载请标明出处: http://blog.csdn.net/u011974987/article/details/50801770; 概述:简单介绍下这个需求的缘由,这段时间因公司业务需要,其中有...

QT国际化,中英文等多语言界面显示的方法

在网上学习了一下QT的国际化用法,最后将自己试成功的方法总结如下: 其中遇到的问题有:生成的ts文件中 代码中的中文 有的不显示,有的显示乱码。 步骤1:

android开发 多语言和国际化(转)

我们建好一个android 的项目后,默认的res下面 有layout、values、drawable等目录 这些都是程序默认的资源文件目录,如果要实现多语言版本的话,我们就要添加要实现语言的对...

android多语言与国际化(记录)

Android 的多语言和国际化网上文章比较多, 我也就不重新写了, 这里主要收录两个比较好的,供技术积累和参考。 1.转载:http://blog.csdn.net/fenghome/articl...

Android 国际化(多语言)

1.  很大程度上,为什么我们能如此方便的实现国际化、分辨率匹配等?      主要就是得益于 Android 中这种独特的资源管理方式。程序员的代码可以不直接和资源发生关系。Android 中...

android国际化(多语言)

android国际化(多语言)

android国际化(多语言)

1.  很大程度上,为什么我们能如此方便的实现国际化、分辨率匹配等?      主要就是得益于 Android 中这种独特的资源管理方式。程序员的代码可以不直接和资源发生关系。Android 中...

Android, IOS 史上最强多语言国际化,不仅第一次会跟随系统,而且会保存用户的语言设置

1.我等屌丝喜欢简单粗暴,首先来一幅图 哥们我是大陆人,当然默认语言是 中文简体,但是我刚刚切换成了繁体了 2.看下配置文件,按照这个格式 ,看图吧,简单粗暴,别问为什么,你就按照这样写,如果...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)