在Android中利用抽象类对外提供系统接口

需求背景

Android系统定制中,无可避免需要对外提供一些定制化的接口,使app能完成一些定制化需求。之前用过aidl文件和jar用于app和系统同步接口,但效果都不尽人意。aidl文件对接口有顺序要求,不好增删改查,且接口调用的逻辑诡异;jar需要单独编译,且不能够直接看到接口信息,需要反编译。经过一番探索,发现可以让app使用抽象类来调用系统中的接口,该抽象类类似C语言中的.h文件,只描述接口,实际实现类在系统framework中。

示意图如下:

原理介绍

CustomManager.java作为中间桥梁,内容如下:

java 复制代码
public abstract class CustomManager {  
    public static CustomManager getInstance(Context context) {  
        return (CustomManager) context.getSystemService("CustomManager");  
    }  
  
    public abstract String getVersion();  
}

app将CustomManager.java导入到项目中,并import即可使用CustomManager中的接口。

为了app导入CustomManager.java后能顺利编译通过,CustomManager.java中不能使用超出标准api以外的类,但可交由抽象方法中的实现(CustomManagerImpl)或后端CustomManagerService去做。

app导入CustomManager.java后, 先调用CustomManager.getInstance(Context context)获取实例,然后再使用接口,如:

java 复制代码
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private CustomManager mCustomManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //实例化
        mCustomManager = CustomManager.getInstance(this)

        //调用具体接口
        mCustomManager.getVersion()
    }
}

CustomManagerImpl.java继承了CustomManager.java并实现了在CustomManager.java中定义的接口:

java 复制代码
public class CustomManagerImpl extends CustomManager {
    private final ICustomManager mService;

    public CustomManagerImpl(Context context, ICustomManager service) {
        mService = service;
        mContext = context;
    }

    public String getVersion() {
        try {
            return mService.getVersion();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "unknow";
    }
}

CustomManagerImpl.java由系统端维护,编译进framework.jar, app在调用CustomManager.getInstance(Context context)后会返回一个CustomManagerImpl实例并转换为CustomManager。 为什么会返回一个CustomManagerImpl实例?因为在系统中注册了服务"CustomManager": SystemServiceRegistry:

java 复制代码
registerService("CustomManager", com.so.CustomManagerImpl.class,
        new CachedServiceFetcher<com.so.CustomManagerImpl>() {
            @Override
            public com.so.CustomManagerImpl createService(ContextImpl ctx)
                    throws ServiceNotFoundException {
                IBinder b = ServiceManager.getService("CustomManagerService");
                ICustomManager service = ICustomManager.Stub.asInterface(b);
                return new com.so.CustomManagerImpl(ctx, service);
            }});

因此在app中只要通过一个字符串"CustomManager"即可得到一个在framework中实现的CustomManagerImpl的实例:

java 复制代码
public abstract class CustomManager {
    public static CustomManager getInstance(Context context) {
        return (CustomManager) context.getSystemService("CustomManager");
    }
}

app获得CustomManager实例后,调用其接口,其实都是在调用CustomManagerImpl的接口。 如mCustomManager.getVersion(),其实走的是CustomManagerImpl.getVersion()。

与后端服务CustomManagerService的交互

CustomManagerImpl虽然在framework中实现,但运行时还在app域,受权限等的限制,能调用的系统功能有限,因此我们进一步在系统中新增一个系统级服务CustomManagerService来实现更复杂的功能。CustomManagerImpl通AIDL来与CustomManagerService交互, 新增aidl文件ICustomManager.aidl:

java 复制代码
interface ICustomManager {
    String getVersion();
}

CustomManagerService继承ICustomManager.Stub, 并实现接口:

java 复制代码
public class CustomManagerService extends ICustomManager.Stub {
    public String getVersion() {
       return "V1.0.0";
    }
}

SystemServiceRegistry在注册服务"CustomManager"时, 也将CustomManagerService的Binder引用传给了CustomManagerImpl.mService,所以在CustomManagerImpl.getVersion()中调用了mService.getVersion()即是调用CustomManagerService.getVersion()。

总结

将抽象类做"头文件"来对外提供接口,有维护简单,逻辑明了,可读性强的优点,甚至可以针对不同需求提供不完全的CustomManager.java来实现接口的隐藏。

相关推荐
June bug9 分钟前
【领域知识】一个休闲游戏产品(安卓和iOS)从0到1
android·ios
zgyhc20509 分钟前
【Android Audio】Android Audio有线设备插拔监听机制
android
ZHANG13HAO10 分钟前
android13 系统强制wifi连接到内网,假装具有互联网能力
android
2501_9151063221 分钟前
iOS 如何绕过 ATS 发送请求,iOS调试
android·ios·小程序·https·uni-app·iphone·webview
JMchen12325 分钟前
Android相机硬件抽象层(HAL)逆向工程:定制ROM的相机优化深度指南
android·开发语言·c++·python·数码相机·移动开发·android studio
_OP_CHEN33 分钟前
【Linux系统编程】(二十五)从路径到挂载:Ext 系列文件系统的 “导航” 与 “整合” 核心揭秘
linux·操作系统·文件系统·c/c++·ext2文件系统·路径解析·挂载分区
ANYOUZHEN9 小时前
bugku shell
android
南宫码农12 小时前
我的电视 - Android原生电视直播软件 完整使用教程
android·开发语言·windows·电视盒子
道亦无名12 小时前
音频数据特征值提取 方法和步骤
android·音视频
Lancker12 小时前
定制侠 一个国产纯血鸿蒙APP的诞生过程
android·华为·智能手机·鸿蒙·国产操作系统·纯血鸿蒙·华为鸿蒙