Android之引用其它已安装或未安装apk文件的资源

本文介绍如何在Android应用中引用未安装或已安装的apk文件资源进行皮肤更换,涉及使用反射技术获取资源,包括核心步骤、代码实现及实例解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android应用有时候会涉及到皮肤的更换问题,在这里,我用一种引用其它已安装或未安装apk文件的资源来说明。

其核心思想就是利用反射来获取。

 

a、引用其它未安装apk文件的资源来说明

       1、首先创建一个application(StyleClient),将其打包称APK并拷贝到/data/目录下

       2、在StyleClient里的Drawable文件夹下随便拷贝进去一张图片,OK。

       3、再创建一个application(StyleHost),编写代码,下面附上。

 

b、引用其它已安装apk文件的资源来说明

      基本步骤同上,只是,要把StyleClient安装一下,不用拷贝。

核心代码:

package org.zqy.stylehost;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import dalvik.system.DexClassLoader;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.RelativeLayout;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		final RelativeLayout tre = (RelativeLayout) findViewById(R.id.root);
		Button btn_1 = (Button) findViewById(R.id.btn_1);//获取未安装的图片
		Button btn_2 = (Button) findViewById(R.id.btn_2);//获取已安装的图片
		btn_2.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				try {
				  tre.setBackground(getTestBContext().getResources()
						.getDrawable(
							getId(getTestBContext().getResources(),
									"drawable", "xiangbi")));
				} catch (NotFoundException e) {
					e.printStackTrace();
				} catch (NameNotFoundException e) {
					e.printStackTrace();
				}
			}
		});
		btn_1.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// 要操作的apk的位置
				String dexPath = "/data/StyleClient.apk";
				// 把apk解压到data\data\当前应用程序
				String dexOuputPath = getApplicationInfo().dataDir;
				// C/C++类库位置
				String libPath = null;
				DexClassLoader localDexClassLoader = new DexClassLoader(
						dexPath, dexOuputPath, libPath, this.getClass()
								.getClassLoader());
				try {
					// 反射drawable内部类
					Class<?> localClass1 = localDexClassLoader
							.loadClass("org.zqy.styleclient.R$drawable");
					// 反射内部类的属性
					Field[] fields = localClass1.getDeclaredFields();
					for (Field f : fields) {
						// 将其属性设置为可读
						f.setAccessible(true);
						System.out.println(f.getName());
						if (f.getName().equals("shui")) {
							int id = f.getInt(new R.id());
							// 设置背景
							tre.setBackground(getPackageResource().getDrawable(
									id));
						}

					}

				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}
			}
		});
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	// 构建apk里的资源
	private Resources getPackageResource() {
		try {
			// 反射出资源管理器
			Class<?> class_AssetManager = Class
					.forName("android.content.res.AssetManager");
			// 创建类的实例
			Object assetMag = class_AssetManager.newInstance();
			// 声明方法,因为addAssetPath是被隐藏的,所以只能通过反射调用
			Method method_addAssetPath = class_AssetManager.getDeclaredMethod(
					"addAssetPath", String.class);
			// 执行方法
			method_addAssetPath.invoke(assetMag, "/data/StyleClient.apk");
			// 为下一行传递参数用的
			Resources res = getResources();
			// 确定用哪个构造函数
			Constructor<?> constructor_Resources = Resources.class
					.getConstructor(class_AssetManager, res.getDisplayMetrics()
							.getClass(), res.getConfiguration().getClass());
			// 执行构造函数
			res = (Resources) constructor_Resources.newInstance(assetMag,
					res.getDisplayMetrics(), res.getConfiguration());
			// 返回/data/StyleCilent.apk的resource实例
			return res;

		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 获取TestB的Context
	 * 
	 * @return
	 * @throws NameNotFoundException
	 */
	private Context getTestBContext() throws NameNotFoundException {

		return createPackageContext("org.zqy.styleclient",
				Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE);
	}

	// 获取已安装APK资源的id
	private int getId(Resources testb, String resType, String resName) {
		return testb.getIdentifier(resName, resType, "org.zqy.styleclient");
	}

}

代码地址:

http://pan.baidu.com/s/11P3jb#dir/path=%2F%E6%88%91%E7%9A%84Android%E7%A4%BA%E4%BE%8B%E7%A8%8B%E5%BA%8F%E4%BB%A3%E7%A0%81

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值