利用createPackageContext()方法实现囊中探物

Context有个createPackageContext方法,可以创建另外一个包的上下文,这个实例不同于它本身的Context实例,但是功能是一样的。


      这个方法有两个参数:
1.packageName  包名,要得到Context的包名
2.flags  标志位,有CONTEXT_INCLUDE_CODE和CONTEXT_IGNORE_SECURITY两个选项。

              CONTEXT_INCLUDE_CODE的意思是包括代码,也就是说可以执行这个包里面的代码。

              CONTEXT_IGNORE_SECURITY的意思是忽略安全警告,如果不加这个标志的话,有些功能是用不了的,会出现安全警告。


利用以上特性,可以实现从别的apk包中获取Resource资源

新建一个目标资源项目,例子的apk包名为"com.test.resource",在src/value/string.xml有一下内容

[html]  view plain copy
  1. <resources>  
  2.   
  3.     <string name="app_name">GetOtherResource</string>  
  4.     <string name="hello_world">Hello world!</string>  
  5.     <string name="title_activity_main">MainActivity</string>  
  6.       
  7.     <string name="message">这个是资源项目的专属string资源</string>  
  8.   
  9. </resources>  

编译运行一下这个简单的项目(相当于在设备上安装该项目的apk)

       好了,现在设备上已经存在包名为“com.test.resource”的apk,此为前提准备,接下来就是怎样获取资源的过程

新建一个测试项目,在main.xml有个显示结果的TextView和一个触发事件的Button,Activity的代码如下:

[html]  view plain copy
  1. public class GetResourceActivity extends Activity {  
  2.   
  3.     private TextView txvA;  
  4.   
  5.     @SuppressLint("ParserError")  
  6.     @Override  
  7.     public void onCreate(Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.         setContentView(R.layout.main);  
  10.   
  11.         txvA = (TextView) findViewById(R.id.txvA);  
  12.   
  13.         ((Button) findViewById(R.id.btnA)).setOnClickListener(new OnClickListener() {  
  14.   
  15.             @Override  
  16.             public void onClick(View v) {  
  17.                   
  18.                 Context context;  
  19.                 try {  
  20.                     context = createPackageContext("com.test.resource", Context.CONTEXT_INCLUDE_CODE  
  21.                             | Context.CONTEXT_IGNORE_SECURITY);  
  22.                     txvA.setText(context.getResources().getText(R.string.message));  
  23.                 } catch (NameNotFoundException e) {  
  24.                     // TODO Auto-generated catch block  
  25.                     e.printStackTrace();  
  26.                 }  
  27.             }  
  28.         });  
  29.     }  
  30. }  

这样,就可以在包名为“ com.test.resource ”的apk存在的情况下获取/res/values/string.xml里面message标签的内容展示在txvA上了。

更进一部探讨,就会发现项目B要获取项目A的资源,在上面的方法中B项目的R.string.message必须跟项目A的一样才能正常编译通过,在很多情况下并不知道A有什么资源,或者在B中存在隐藏的界面并且在某种情况下将其展现,显然是不够灵活的。

进一步利用java的反射机制,通过利用资源名称反推出资源的ID号,利用一下方法可以实现

[html]  view plain copy
  1. /***  
  2.      * 通过资源名称反推出资源ID号  
  3.      *   
  4.      * @param clazz 目标资源的R.java  
  5.      * @param className R.java的内部类,如layout,string,drawable...  
  6.      * @param name 资源名称  
  7.      * @return  
  8.      */  
  9.     private int getResourseIdByName(Class clazz, String className, String name) {  
  10.         int id = 0;  
  11.         try {  
  12.   
  13.             Class[] classes = clazz.getClasses(); // 获取R.java里的所有静态内部类  
  14.             Class desireClass = null;  
  15.   
  16.             for (int i = 0; i < classes.length; i++) {  
  17.                 if (classes[i].getName().split("\\$")[1].equals(className)) { // 查找指定的静态内部类  
  18.                     desireClass = classes[i];  
  19.                     break;  
  20.                 }  
  21.             }  
  22.             if (desireClass != null)  
  23.                 id = desireClass.getField(name).getInt(desireClass); // 从指定的静态内部类获得资源编号  
  24.         } catch (IllegalArgumentException e) {  
  25.             e.printStackTrace();  
  26.         } catch (SecurityException e) {  
  27.             e.printStackTrace();  
  28.         } catch (IllegalAccessException e) {  
  29.             e.printStackTrace();  
  30.         } catch (NoSuchFieldException e) {  
  31.             e.printStackTrace();  
  32.         }  
  33.   
  34.         return id;  
  35.     }  
  36. }  

这样Button按钮里面的写法应该这样

[html]  view plain copy
  1. ((Button) findViewById(R.id.btnA)).setOnClickListener(new OnClickListener() {  
  2.   
  3.             @Override  
  4.             public void onClick(View v) {  
  5.   
  6.                 Context context;  
  7.                 try {  
  8.                     context = createPackageContext("com.test.resource", Context.CONTEXT_INCLUDE_CODE  
  9.                             | Context.CONTEXT_IGNORE_SECURITY);  
  10.                     Class cls = context.getClassLoader().loadClass("com.test.resource.R"); // 获得目标apk的R类  
  11.                     txvA.setText(context.getResources().getText(getResourseIdByName(cls, "string", "message")));  
  12.                 } catch (NameNotFoundException e) {  
  13.                     e.printStackTrace();  
  14.                 } catch (ClassNotFoundException e) {  
  15.                     e.printStackTrace();  
  16.                 }  
  17.             }  
  18.         });  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值