赞
踩
最近想总结一下关于应用如何封装自己的SDK给第三方应用使用,提供jar包给第三方使用是现在比较常见的方式,方式有很多种,但是具体的大体思路都是一样的,今天写了一个SDK封装的大体框架Demo,方便后期查查阅:
工具基于AndroidStudio 3.6.3版本
大体的设计思路分为三个步骤
第一: 服务端 作为服务端 我们需要建立自己的aidl 以及实现类 方便第三方调用的时候 将服务端代理的句柄传给SDK
第二: SDK作为服务端和客户端的中间代理,可以直接拿到服务代理对象进行操作,并暴露给客户端可见的实用类和接口回调类
第三: 客户端只能使用SDK暴露出来的接口进行操作,不持有服务端代理.
具体的逻辑可以下图:
下面是对Demo的详解,个人建议 直接将Demo下载下来阅读即可,后面文章过于繁琐,时间充足的话建议阅读.
如图本项目分为三个 :
第一个是 客户端 app是个应用.
第二个是 SDK mylibrary是个lib库.
第三个是 clienapp 是个应用.
整体的架构设计如下图:
mylibrary是一个lib项目不是可运行项目
首先需要确定的是需要AIDL做什么, 只有确定了具体需要做的功能才能确定mylibrary项目中新建aidl文件之中的方法,本案例的设计一个是数据传递 一个是 数据回调.
在 MyRemoteCtrl.aidl中做了如下操作
- package com.example.mylibrary;
-
- import com.example.mylibrary.MySDKStatusCallBack;
-
- interface MyRemoteCtrl {
- //传递数据
- void sendMessage(String msg);
- //建立死亡链接
- void linkToDeath(IBinder binder);
- //断开死亡链接
- void unlinkToDeath(IBinder binder);
- //注册callback
- void registerMySDKStatusCallBack(MySDKStatusCallBack mySDKStatusCallBack);
-
- void unregisterMySDKStatusCallBack(MySDKStatusCallBack mySDKStatusCallBack);
- }

MySDKStatusCallBack.aidl中做了三个回调函数
- // MySDKStatusCallBack.aidl
- package com.example.mylibrary;
-
- // Declare any non-default types here with import statements
-
- interface MySDKStatusCallBack {
-
- void statusCallBackVisible();
-
- void statusCallBackInvisible();
-
- void sendMessage(String message);
- }
创建和aidl用户具体的交互基类Controller.java基本 确定SDK的基本功能 因为需要和 service进行绑定所以继承于 ServiceConnection 实现 ServiceConnection的方法.
- public interface Controller extends ServiceConnection {
- /**
- * init sdk
- *
- * @param context context
- * @return result
- */
- int init(Context context);
-
- /**
- * setStateCallback
- *
- * @param remoteSDKStatusCallBack
- */
-
- void setStateCallback(RemoteSDKStatusCallBack remoteSDKStatusCallBack);
-
-
- void setMessage(String msg);
-
- /***
- * release sdk
- */
- void release();
-
- }

有了上面的AIDL文件之后开始确定 SDK的入口类MyLibSDK.java 这个类是需要暴露给第三方的使用的入口类,别人使用jar包的时候 只能通过 MyLibSDK.java类进行操作.
- package com.example.mylibrary;
-
- import android.content.Context;
-
- import com.example.mylibrary.base.Controller;
- import com.example.mylibrary.callback.RemoteSDKStatusCallBack;
- import com.example.mylibrary.imp.MyController;
-
- public class MyLibSDK {
- private volatile static MyLibSDK mInstance;
- private Controller mController;
-
- private MyLibSDK() {
- }
-
- public static MyLibSDK getInstance() {
- if (mInstance == null) {
- synchronized (MyLibSDK.class) {
- if (mInstance == null) {
- mInstance = new MyLibSDK();
- }
- }
- }
- return mInstance;
- }
-
- /**
- * 初始化SDK
- *
- * @param context context
- * @return result
- */
- public int init(Context context) {
- mController = MyController.getInstance();
- return mController.init(context);
- }
-
- /***
- * 发送消息
- */
- public void setMessage(String msg) {
- if (mController != null) {
- mController.setMessage(msg);
- }
-
- }
-
- /***
- * 释放SDK
- */
- public void release() {
- if (mController != null) {
- mController.release();
- }
- }
-
- /***
- * 设置监听
- */
- public void setStateCallback(RemoteSDKStatusCallBack remoteSDKStatusCallBack) {
- if (mController != null) {
- mController.setStateCallback(remoteSDKStatusCallBack);
- }
- }
-
- }

具体的业务实现类是 MyController.java 它持有 MySDKStatusCallBack和 MyRemoteCtrl 对象 ,MySDKStatusCallBack MyRemoteCtrl 是aidl的类系统对创建对应的java文件如果没有创建 就使用编译器clean 一下项目 然后再build一下 项目
其实MyController.java ;类中的的 MyRemoteCtrl 就是绑定服务端之后服务端返回的代理对象, MyController.java 持有代理对象进行和服务端的交互操作.
- package com.example.mylibrary.imp;
-
- import android.app.Service;
- import android.content.ComponentName;
- import android.content.Context;
- import android.content.Intent;
- import android.os.IBinder;
- import android.os.RemoteException;
- import android.util.Log;
-
- import com.example.mylibrary.MyRemoteCtrl;
- import com.example.mylibrary.MySDKStatusCallBack;
- import com.example.mylibrary.base.Controller;
- import com.example.mylibrary.callback.RemoteSDKStatusCallBack;
-
- public class MyController implements Controller {
-
-
- private MyRemoteCtrl mMyRemoteCtrl;
- private RemoteSDKStatusCallBack mRemoteSDKStatusCallBack;
- private boolean isbind;
- private volatile static Controller mInstance;
- protected Context mContext;
-
- //死亡链接
- private MySDKStatusCallBack mMySDKStatusCallBack = new MySDKStatusCallBack.Stub() {
-
- @Override
- public void statusCallBackVisible() throws RemoteException {
- mRemoteSDKStatusCallBack.statusCallBackVisible();
- }
-
- @Override
- public void statusCallBackInvisible() throws RemoteException {
- mRemoteSDKStatusCallBack.statusCallBackInvisible();
- }
-
- @Override
- public void sendMessage(String message) throws RemoteException {
- mRemoteSDKStatusCallBack.sendMessage(message);
- }
-
- };
-
-
- private MyController() {
- }
-
- @Override
- public int init(Context context) {
- //初始化服务
- Log.d("mysdk", " sdk 初始化服务 ");
- mContext = context;
- return initService();
- }
-
- @Override
- public void setStateCallback(RemoteSDKStatusCallBack remoteSDKStatusCallBack) {
- Log.d("mysdk", " sdk setStateCallback ");
- this.mRemoteSDKStatusCallBack = remoteSDKStatusCallBack;
- }
-
- private int initService() {
- Log.d("mysdk", " sdk initService ");
- Intent intent = new Intent("com.example.androidsdkdemo.service.MySDKService");
- intent.setClassName("com.example.androidsdkdemo", "com.example.androidsdkdemo.service.MySDKService");
- isbind = mContext.bindService(intent, this, Service.BIND_AUTO_CREATE);
- return 0;
- }
-
- @Override
- public void setMessage(String msg) {
- try {
- Log.d("mysdk", " sdk setMessage ");
- mMyRemoteCtrl.sendMessage(msg);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
-
- @Override
- public void release() {
- Log.d("mysdk", " sdk release ");
- //SDK内部做释放操作
-
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- Log.d("mysdk", " sdk onServiceConnected ");
- if (service == null) {
- if (mMyRemoteCtrl != null) {
- try {
- mMyRemoteCtrl.unlinkToDeath(mMySDKStatusCallBack.asBinder());
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- mMyRemoteCtrl = null;
- } else {
- mMyRemoteCtrl = MyRemoteCtrl.Stub.asInterface(service);
- if (mMyRemoteCtrl != null) {
- try {
- mMyRemoteCtrl.linkToDeath(mMySDKStatusCallBack.asBinder());
- } catch (RemoteException e) {
- e.printStackTrace();
- }
-
- try {
- mMyRemoteCtrl.registerMySDKStatusCallBack(mMySDKStatusCallBack);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- Log.d("mysdk", " sdk onServiceDisconnected ");
- if (mMyRemoteCtrl != null) {
- try {
- mMyRemoteCtrl.unregisterMySDKStatusCallBack(mMySDKStatusCallBack);
- mMyRemoteCtrl.unlinkToDeath(mMySDKStatusCallBack.asBinder());
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- mMyRemoteCtrl = null;
- }
-
- public static Controller getInstance() {
- if (mInstance == null) {
- synchronized (MyController.class) {
- if (mInstance == null) {
- mInstance = new MyController();
- }
- }
- }
- return mInstance;
- }
- }

MyController.java 里有一个 RemoteSDKStatusCallBack对象,这个对象是暴露给客户 让客户进行注册的类对象属于SDK自己的CallBack类,当客户端设置这个Callback之后 SDK中就持有了客户端实现的Callback对象实例, SDK在接收到 服务端的回调之后 可以通过RemoteSDKStatusCallBack 实例回调给客户.这样做有个好处,客户端不会持有服务端的代理对象和不会持有SDK中的AIDL的回调实例,SDK中实现的AIDL具体的Callback就对客户是不可见的,此处RemoteSDKStatusCallBack.java 内部的名字和MySDKStatusCallBack.aidl的相同,也可以根据自己的需求添加接口,或者修改名称.
- package com.example.mylibrary.callback;
-
- public interface RemoteSDKStatusCallBack {
- void statusCallBackVisible();
-
- void statusCallBackInvisible();
-
- void sendMessage(String message);
- }
之后进行进行生成jar包的配置,在mylibrary 的build.gradle 里面添加如下代码
注意 from('build/intermediates/aar_main_jar/debug/') 可能路径不同的版本不同需要搜索一下 classes.jar 路径 进行替换即可
- task makeJar(type:Copy){
- //如果之前存在,则先删除
- delete 'build/libs/mysdklib.jar'
- //设置拷贝的文件
- from('build/intermediates/aar_main_jar/debug/')
- //生成jar包后的文件目录位置
- into('build/libs/')
- //include,exclude参数来设置过滤
- include('classes.jar')
- //重命名
- rename('classes.jar','mysdklib.jar')
- }
- makeJar.dependsOn(build)
生成jar包的两种方式
1,可以在根目录执行 ./gradlew makeJar
2.或者在右上角的 Gradle --> mylibrary-->Tasks --> other --> makeJar 双击makeJar 生成
到此 jar包的生成已经做完了.
首先需要将 mylibrary 导入到app中,因为需要要到SDK中的aidl,在APP项目中的build.gradle 中的 dependencies 添加如下代码不然服务端使用不了mylibrary中的aidl文件.
implementation project(':mylibrary')
MySDKService.java 中的内部类 MyRemoteCtrlImpl 是服务的代理类 也是SDK端拿到的 MyRemoteCtrl代理对象类,服务中我们可以控制代理对象具体功能,那么也就间接的控制了第三方可以使用服务端app的那些功能,我们这里这里没有做具体的控制逻辑,只是将接收到的数据进行返回操作即可.
- package com.example.androidsdkdemo.service;
-
- import android.app.Service;
- import android.content.Intent;
- import android.os.IBinder;
- import android.os.RemoteException;
- import android.util.Log;
-
- import androidx.annotation.Nullable;
-
- import com.example.mylibrary.MySDKStatusCallBack;
- import com.example.mylibrary.MyRemoteCtrl;
-
- public class MySDKService extends Service {
-
- private MyRemoteCtrlImpl mCarcorderRemoteCtrl = new MyRemoteCtrlImpl();
- private MySDKStatusCallBack mMySDKStatusCallBack = null;
- @Nullable
- @Override
- public IBinder onBind(Intent intent) {
- //返回内部代理对象给调用端
- return mCarcorderRemoteCtrl.asBinder();
- }
-
-
- public class MyRemoteCtrlImpl extends MyRemoteCtrl.Stub {
- private IBinder mBinder = null;
- private Object deathRecipient;
-
- @Override
- public void sendMessage(String msg) throws RemoteException {
- if (mMySDKStatusCallBack != null) {
- mMySDKStatusCallBack.sendMessage("我已经接收到你的数据返回给你 = " + msg);
- }
- }
-
- @Override
- public void linkToDeath(IBinder binder) throws RemoteException {
- Log.d("mysdk"," 服务端 建立死亡链接 ");
- mBinder = binder;
- binder.linkToDeath(mDeathRecipient, 0);
- }
-
-
- @Override
- public void unlinkToDeath(IBinder binder) throws RemoteException {
- Log.d("mysdk"," 服务端 断开客户端死亡链接 ");
- binder.unlinkToDeath(mDeathRecipient, 0);
- mBinder = null;
- }
-
- @Override
- public void registerMySDKStatusCallBack(MySDKStatusCallBack mySDKStatusCallBack) throws RemoteException {
- Log.d("mysdk"," 服务端 接收到 registerMySDKStatusCallBack ");
- mMySDKStatusCallBack = mySDKStatusCallBack;
- // mMySDKStatusCallBack 为第三方通过SDK传递过来的 对象 调用 mySDKStatusCallBack.statusCallBackInvisible()
- // 相当于持有 MySDKStatusCallBack mMySDKStatusCallBack
-
- //这里不做操作直接返回即可
- if (mMySDKStatusCallBack != null) {
- mySDKStatusCallBack.statusCallBackInvisible();
- }
- }
-
- @Override
- public void unregisterMySDKStatusCallBack(MySDKStatusCallBack mySDKStatusCallBack) throws RemoteException {
- Log.d("mysdk"," 服务端 接收到 unregisterMySDKStatusCallBack ");
- mMySDKStatusCallBack = null;
- }
- }
-
-
-
- IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
- @Override
- public void binderDied() {
- /* if (mMySDKStatusCallBack != null) {
- try {
- mMySDKStatusCallBack.statusCallBackInvisible();
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }*/
-
- //客户端可以执行释放操作
- Log.d("mysdk"," 调用端已经死亡");
- }
-
- };
-
- }

在AndroidManifest.xml中天机如下代码 android:enabled="true" android:exported="true" 4.4 版本之后必须添加
- <service
- android:name="com.example.androidsdkdemo.service.MySDKService"
- android:enabled="true"
- android:exported="true">
- </service>
到此处服务端添加完成,此时可以运行一下服务端,先安装到手机上方便后期直接调用.
将mysdklib.jar 拷贝到 AndroidSDKDemo/clienapp/libs 下面 并且在 clienapp 项目 中 build.gradle的dependencies中
添加如下:
implementation files('libs/mysdklib.jar')
在 MainActivity 使用我们的sdk jar包中的类 MyLibSDK 进行服务端交互
- package com.example.clienapp;
-
- import androidx.appcompat.app.AppCompatActivity;
-
- import android.os.Bundle;
- import android.util.Log;
- import android.view.View;
-
- import com.example.mylibrary.MyLibSDK;
- import com.example.mylibrary.callback.RemoteSDKStatusCallBack;
-
- public class MainActivity extends AppCompatActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- MyLibSDK.getInstance().init(this);
- MyLibSDK.getInstance().setStateCallback(new RemoteSDKStatusCallBack() {
- @Override
- public void statusCallBackVisible() {
- Log.d("mysdk"," 客户端 statusCallBackVisible ");
- }
-
- @Override
- public void statusCallBackInvisible() {
- Log.d("mysdk"," 客户端 statusCallBackInvisible ");
- }
-
- @Override
- public void sendMessage(String s) {
- Log.d("mysdk"," 客户端 sendMessage " + s);
- }
- });
- }
-
-
- public void sedmessage(View view) {
- Log.d("mysdk"," 客户端 sendMessage 我是客户端 " );
- MyLibSDK.getInstance().setMessage("我是客户端");
- }
-
- }

运行结果如下:
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。