Android动态换肤(三、安装主题apk方式)

时间:2023-03-09 02:51:29
Android动态换肤(三、安装主题apk方式)

相比之前免安装的方式,这种方法需要用户下载并安装皮肤apk,程序写起来比免安装的要简单很多,像很多系统主题就是通过这种方式实现的。

这种方式的思路是,从所有已安装的应用程序中遍历出皮肤程序(根据特定包名区分),然后选中某个主题后,将此皮肤应用的包名保存到主应用中,需要获取资源时,通过皮肤包名得到皮肤应用的Context,然后便可得到Resources,从而获取到皮肤apk中的资源。下面看看关键步骤的代码:

遍历所有应用程序,筛选出皮肤应用程序

/**
 * 获取所有已安装的皮肤主题
 * @return
 */
private ArrayList<PackageInfo> getAllSkin() {
    ArrayList<PackageInfo> skinList = new ArrayList<PackageInfo>();
    List<PackageInfo> packs = getPackageManager().getInstalledPackages(0);
    for (PackageInfo p : packs) {
        if (isSkinPackage(p.packageName)) {
            skinList.add(p);
        }
    }
    return skinList;
}
/**
* 判断是否是皮肤主题
 */
private boolean isSkinPackage(String packageName) {
    String rex = Contact.SKIN_APP_PACKNAME+"\\w";
    Pattern pattern = Pattern.compile(rex);
    Matcher matcher = pattern.matcher(packageName);
    return matcher.find();
}

获取皮肤资源

此处需要注意一点,在拿到皮肤apk的Resources之后,获取资源的时候不能直接使用R.xx.xx,因为这个时候的R是主应用中的R,而不是皮肤apk中的R,如果主应用和皮肤apk的资源不一样(种类和数量),他们的R文件中的资源ID值是不一样的,这样就会找不到资源。可以通过getIdentifier方法根据资源名称获取资源ID,这样皮肤apk中的资源可以只有那些需要做改变的(并不需要和宿主应用中一模一样),并保持和宿主中资源名称相同即可。

private void changeSkin(){
    String skinPackName = mContext.getSharedPreferences(Contact.SP_NAME, Context.MODE_PRIVATE).getString(Contact.SP_KEY_SKIN, "");
    if(TextUtils.isEmpty(skinPackName)){
        //使用默认皮肤
        layout.setBackgroundDrawable(getResources().getDrawable(R.drawable.activity_bg));
    }else{
        //使用皮肤主题
        try {
            final Context context = createPackageContext(skinPackName, Context.CONTEXT_IGNORE_SECURITY);
            //此处应该根据皮肤apk中的资源ID找到皮肤资源,而不能直接用本应用中的R
            //如果皮肤资源和应用中的资源完全一样(数量和种类)才能直接使用应用中的R
            //layout.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.activity_bg));
            Resources resources = context.getResources();
            int indentify = resources.getIdentifier(context.getPackageName()+":drawable/activity_bg", null, null);
            if(indentify>0){
                layout.setBackgroundDrawable(context.getResources().getDrawable(indentify));
            }
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }
    }
}

效果图:

Android动态换肤(三、安装主题apk方式)

源码下载:

https://github.com/openXu/SkinChange3

Android动态换肤(三、安装主题apk方式)