Android换肤方案分析

简介: ## 0x0 背景 无论是出于用户个性化的考虑,或者是不同场景下的氛围渲染,客户端应用存在着换肤的需求。本文举出三种常见的换肤方案,并加以对比,以作后续参考。无论何种方案,换肤的核心都包含皮肤的管理,皮肤的加载,以及皮肤的生效。不同的方案在解决这些问题上有不同的思路。 ## 0x1 手动重新设置UI资源 这种方式最简单,在业务代码里面手动写设置新皮肤的逻辑,当新皮肤下发时,回调该逻辑重新

0x0 背景

无论是出于用户个性化的考虑,或者是不同场景下的氛围渲染,客户端应用存在着换肤的需求。本文举出三种常见的换肤方案,并加以对比,以作后续参考。无论何种方案,换肤的核心都包含皮肤的管理,皮肤的加载,以及皮肤的生效。不同的方案在解决这些问题上有不同的思路。

0x1 手动重新设置UI资源

这种方式最简单,在业务代码里面手动写设置新皮肤的逻辑,当新皮肤下发时,回调该逻辑重新设置UI资源,就达到了换肤的逻辑。这种方案思路简单,但是业务入侵的,需要手动写代码,有维护成本。而且由于需要手动写重新设置UI的逻辑,因此一般不会对所有的控件都更换UI资源,因此换肤的范围存在局限性。

public void onSkinChanged(JSONObject newSkin) {
    int newTextColor = newSkin.optInt("my_text_color");
    TextView myTextView = (TextView)findViewById("R.id.mytext");
    myTextView.setTextColor(newTextColor);

    String newImageUrl = newSkin.optString("my_img_url");
    UrlImageView myImageView = (UrlImageView)findViewById("R.id.myimage");
    myImageView.setImageUrl(newImageUrl);
}

0x2 自定义资源框架

Android原生的资源都是通过Resources加载定义在res目录下的xml中的资源。由于res目录下的资源是随打包发布的,因此无法做到动态替换。所以这里的思路是自定义一个CustomResources,并自定义resources目录,里面区分default,night, custom等等。default目录下是默认资源,其他目录下是特定场景的皮肤资源,其id和default目录保持一致,就可以实现替换。

resources
    |--- default
            |--- res
            |--- drawable
    |--- night
            |--- res
            |--- drawable

CustomResources可以加载APK包里面的默认资源,也可以加载从服务端下发的资源。在应用开发过程中,不能再使用系统的Resources,必须使用CustomResources,否则无法实现换肤。

    TextView myTextView = (TextView)findViewById("R.id.mytext");
    myTextView.setTextColor(getCustomResrouce().getColor(R.color.mytextcolor));

当然至此为止还不能cover布局xml中直接使用资源id的场景,如果要cover,需要hook系统resources。这种方式需要在应用开发之初就有换肤的设计,开发团队内部约定统一用CustomResources而不用系统的资源。

0x3 Hook系统LayoutInflater

这种思路是hook系统的LayoutInflater,在解析布局xml生成View的时候,替换成继承了换肤逻辑的子类。ximsfei/Android-skin-support是这种思路的代表。替换LayoutInflater的方式是:

   private void installLayoutFactory(Context context) {
        LayoutInflater layoutInflater = LayoutInflater.from(context);
        try {
            Field field = LayoutInflater.class.getDeclaredField("mFactorySet");
            field.setAccessible(true);
            field.setBoolean(layoutInflater, false);
            LayoutInflaterCompat.setFactory(layoutInflater, getSkinDelegate(context));
        } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }

ximsfei/Android-skin-support的实现方案中,下发皮肤其实是在一个只包含资源文件的APK文件中,保证资源APK中的资源命名和默认的保持一致就能实现替换。读取APK文件中的资源的方式是:

    public Resources getSkinResources(String skinPkgPath) {
        try {
            AssetManager assetManager = AssetManager.class.newInstance();
            Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
            addAssetPath.invoke(assetManager, skinPkgPath);

            Resources superRes = mAppContext.getResources();
            return new Resources(assetManager, superRes.getDisplayMetrics(), superRes.getConfiguration());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

这种方式对于应用开发者来说几乎是透明的,对于业务也没有侵入性,尤其是已有的应用代码上迭代增加换肤功能,这是一种比较好的方式。

目录
相关文章
|
24天前
|
安全 Android开发 数据安全/隐私保护
深入探讨iOS与Android系统安全性对比分析
在移动操作系统领域,iOS和Android无疑是两大巨头。本文从技术角度出发,对这两个系统的架构、安全机制以及用户隐私保护等方面进行了详细的比较分析。通过深入探讨,我们旨在揭示两个系统在安全性方面的差异,并为用户提供一些实用的安全建议。
|
3月前
|
开发工具 Android开发 Swift
安卓与iOS开发环境对比分析
在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统无疑是主角。它们各自拥有独特的特点和优势,为开发者提供了不同的开发环境和工具。本文将深入浅出地探讨安卓和iOS开发环境的主要差异,包括开发工具、编程语言、用户界面设计、性能优化以及市场覆盖等方面,旨在帮助初学者更好地理解两大平台的开发特点,并为他们选择合适的开发路径提供参考。通过比较分析,我们将揭示不同环境下的开发实践,以及如何根据项目需求和目标受众来选择最合适的开发平台。
51 2
|
2月前
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
60 15
Android 系统缓存扫描与清理方法分析
|
2月前
|
存储 Linux Android开发
Android底层:通熟易懂分析binder:1.binder准备工作
本文详细介绍了Android Binder机制的准备工作,包括打开Binder驱动、内存映射(mmap)、启动Binder主线程等内容。通过分析系统调用和进程与驱动层的通信,解释了Binder如何实现进程间通信。文章还探讨了Binder主线程的启动流程及其在进程通信中的作用,最后总结了Binder准备工作的调用时机和重要性。
Android底层:通熟易懂分析binder:1.binder准备工作
|
3月前
|
安全 Android开发 数据安全/隐私保护
探索安卓与iOS的安全性差异:技术深度分析与实践建议
本文旨在深入探讨并比较Android和iOS两大移动操作系统在安全性方面的不同之处。通过详细的技术分析,揭示两者在架构设计、权限管理、应用生态及更新机制等方面的安全特性。同时,针对这些差异提出针对性的实践建议,旨在为开发者和用户提供增强移动设备安全性的参考。
143 3
|
2月前
|
开发工具 Android开发 Swift
安卓与iOS开发环境的差异性分析
【10月更文挑战第8天】 本文旨在探讨Android和iOS两大移动操作系统在开发环境上的不同,包括开发语言、工具、平台特性等方面。通过对这些差异性的分析,帮助开发者更好地理解两大平台,以便在项目开发中做出更合适的技术选择。
|
3月前
|
开发框架 Dart 前端开发
Android 跨平台方案对比之Flutter 和 React Native
本文对比了 Flutter 和 React Native 这两个跨平台移动应用开发框架。Flutter 使用 Dart 语言,提供接近原生的性能和丰富的组件库;React Native 则基于 JavaScript,具备庞大的社区支持和灵活性。两者各有优势,选择时需考虑团队技能和项目需求。
387 8
|
3月前
|
安全 Linux Android开发
探索安卓与iOS的安全性差异:技术深度分析
本文深入探讨了安卓(Android)和iOS两个主流操作系统平台在安全性方面的不同之处。通过比较它们在架构设计、系统更新机制、应用程序生态和隐私保护策略等方面的差异,揭示了每个平台独特的安全优势及潜在风险。此外,文章还讨论了用户在使用这些设备时可以采取的一些最佳实践,以增强个人数据的安全。
|
4月前
|
Java 开发工具 Android开发
安卓与iOS开发环境对比分析
【8月更文挑战第20天】在移动应用开发的广阔天地中,Android和iOS两大平台各自占据着重要的位置。本文将深入探讨这两种操作系统的开发环境,从编程语言到开发工具,从用户界面设计到性能优化,以及市场趋势对开发者选择的影响。我们旨在为读者提供一个全面的比较视角,帮助理解不同平台的优势与挑战,并为那些站在选择十字路口的开发者提供有价值的参考信息。
102 17
|
3月前
|
Web App开发 网络协议 Android开发
Android平台一对一音视频通话方案大比拼:WebRTC VS RTMP VS RTSP,谁才是王者?
【9月更文挑战第4天】本文详细对比了在Android平台上实现一对一音视频通话时常用的WebRTC、RTMP及RTSP三种技术方案。从技术原理、性能表现与开发难度等方面进行了深入分析,并提供了示例代码。WebRTC适合追求低延迟和高质量的场景,但开发成本较高;RTMP和RTSP则在简化开发流程的同时仍能保持较好的传输效果,适用于不同需求的应用场景。
174 1