当前位置:   article > 正文

Android 应用提供SDK Jar包给第三方使用 (设计思路 以及实现步骤)_android 开发sdk怎么根据key开放接口给第三方使用

android 开发sdk怎么根据key开放接口给第三方使用

最近想总结一下关于应用如何封装自己的SDK给第三方应用使用,提供jar包给第三方使用是现在比较常见的方式,方式有很多种,但是具体的大体思路都是一样的,今天写了一个SDK封装的大体框架Demo,方便后期查查阅:

工具基于AndroidStudio 3.6.3版本

AndroidSDKDemo

大体的设计思路分为三个步骤

第一: 服务端 作为服务端 我们需要建立自己的aidl 以及实现类 方便第三方调用的时候 将服务端代理的句柄传给SDK

第二: SDK作为服务端和客户端的中间代理,可以直接拿到服务代理对象进行操作,并暴露给客户端可见的实用类和接口回调类

第三: 客户端只能使用SDK暴露出来的接口进行操作,不持有服务端代理.

具体的逻辑可以下图:

下面是对Demo的详解,个人建议 直接将Demo下载下来阅读即可,后面文章过于繁琐,时间充足的话建议阅读.

 

如图本项目分为三个 :

第一个是 客户端 app是个应用.

第二个是 SDK mylibrary是个lib库.

第三个是 clienapp 是个应用.

 

整体的架构设计如下图:

 

 第一步先编写SDK(mylibrary)  

 

mylibrary是一个lib项目不是可运行项目 

首先需要确定的是需要AIDL做什么, 只有确定了具体需要做的功能才能确定mylibrary项目中新建aidl文件之中的方法,本案例的设计一个是数据传递 一个是 数据回调.

在 MyRemoteCtrl.aidl中做了如下操作

  1. package com.example.mylibrary;
  2. import com.example.mylibrary.MySDKStatusCallBack;
  3. interface MyRemoteCtrl {
  4. //传递数据
  5. void sendMessage(String msg);
  6. //建立死亡链接
  7. void linkToDeath(IBinder binder);
  8. //断开死亡链接
  9. void unlinkToDeath(IBinder binder);
  10. //注册callback
  11. void registerMySDKStatusCallBack(MySDKStatusCallBack mySDKStatusCallBack);
  12. void unregisterMySDKStatusCallBack(MySDKStatusCallBack mySDKStatusCallBack);
  13. }

MySDKStatusCallBack.aidl中做了三个回调函数

  1. // MySDKStatusCallBack.aidl
  2. package com.example.mylibrary;
  3. // Declare any non-default types here with import statements
  4. interface MySDKStatusCallBack {
  5. void statusCallBackVisible();
  6. void statusCallBackInvisible();
  7. void sendMessage(String message);
  8. }

创建和aidl用户具体的交互基类Controller.java基本 确定SDK的基本功能 因为需要和 service进行绑定所以继承于 ServiceConnection 实现 ServiceConnection的方法.

  1. public interface Controller extends ServiceConnection {
  2. /**
  3. * init sdk
  4. *
  5. * @param context context
  6. * @return result
  7. */
  8. int init(Context context);
  9. /**
  10. * setStateCallback
  11. *
  12. * @param remoteSDKStatusCallBack
  13. */
  14. void setStateCallback(RemoteSDKStatusCallBack remoteSDKStatusCallBack);
  15. void setMessage(String msg);
  16. /***
  17. * release sdk
  18. */
  19. void release();
  20. }

有了上面的AIDL文件之后开始确定 SDK的入口类MyLibSDK.java 这个类是需要暴露给第三方的使用的入口类,别人使用jar包的时候 只能通过 MyLibSDK.java类进行操作.

  1. package com.example.mylibrary;
  2. import android.content.Context;
  3. import com.example.mylibrary.base.Controller;
  4. import com.example.mylibrary.callback.RemoteSDKStatusCallBack;
  5. import com.example.mylibrary.imp.MyController;
  6. public class MyLibSDK {
  7. private volatile static MyLibSDK mInstance;
  8. private Controller mController;
  9. private MyLibSDK() {
  10. }
  11. public static MyLibSDK getInstance() {
  12. if (mInstance == null) {
  13. synchronized (MyLibSDK.class) {
  14. if (mInstance == null) {
  15. mInstance = new MyLibSDK();
  16. }
  17. }
  18. }
  19. return mInstance;
  20. }
  21. /**
  22. * 初始化SDK
  23. *
  24. * @param context context
  25. * @return result
  26. */
  27. public int init(Context context) {
  28. mController = MyController.getInstance();
  29. return mController.init(context);
  30. }
  31. /***
  32. * 发送消息
  33. */
  34. public void setMessage(String msg) {
  35. if (mController != null) {
  36. mController.setMessage(msg);
  37. }
  38. }
  39. /***
  40. * 释放SDK
  41. */
  42. public void release() {
  43. if (mController != null) {
  44. mController.release();
  45. }
  46. }
  47. /***
  48. * 设置监听
  49. */
  50. public void setStateCallback(RemoteSDKStatusCallBack remoteSDKStatusCallBack) {
  51. if (mController != null) {
  52. mController.setStateCallback(remoteSDKStatusCallBack);
  53. }
  54. }
  55. }

具体的业务实现类是 MyController.java 它持有 MySDKStatusCallBack和 MyRemoteCtrl 对象 ,MySDKStatusCallBack MyRemoteCtrl 是aidl的类系统对创建对应的java文件如果没有创建 就使用编译器clean 一下项目 然后再build一下 项目

其实MyController.java ;类中的的 MyRemoteCtrl 就是绑定服务端之后服务端返回的代理对象, MyController.java 持有代理对象进行和服务端的交互操作.

  1. package com.example.mylibrary.imp;
  2. import android.app.Service;
  3. import android.content.ComponentName;
  4. import android.content.Context;
  5. import android.content.Intent;
  6. import android.os.IBinder;
  7. import android.os.RemoteException;
  8. import android.util.Log;
  9. import com.example.mylibrary.MyRemoteCtrl;
  10. import com.example.mylibrary.MySDKStatusCallBack;
  11. import com.example.mylibrary.base.Controller;
  12. import com.example.mylibrary.callback.RemoteSDKStatusCallBack;
  13. public class MyController implements Controller {
  14. private MyRemoteCtrl mMyRemoteCtrl;
  15. private RemoteSDKStatusCallBack mRemoteSDKStatusCallBack;
  16. private boolean isbind;
  17. private volatile static Controller mInstance;
  18. protected Context mContext;
  19. //死亡链接
  20. private MySDKStatusCallBack mMySDKStatusCallBack = new MySDKStatusCallBack.Stub() {
  21. @Override
  22. public void statusCallBackVisible() throws RemoteException {
  23. mRemoteSDKStatusCallBack.statusCallBackVisible();
  24. }
  25. @Override
  26. public void statusCallBackInvisible() throws RemoteException {
  27. mRemoteSDKStatusCallBack.statusCallBackInvisible();
  28. }
  29. @Override
  30. public void sendMessage(String message) throws RemoteException {
  31. mRemoteSDKStatusCallBack.sendMessage(message);
  32. }
  33. };
  34. private MyController() {
  35. }
  36. @Override
  37. public int init(Context context) {
  38. //初始化服务
  39. Log.d("mysdk", " sdk 初始化服务 ");
  40. mContext = context;
  41. return initService();
  42. }
  43. @Override
  44. public void setStateCallback(RemoteSDKStatusCallBack remoteSDKStatusCallBack) {
  45. Log.d("mysdk", " sdk setStateCallback ");
  46. this.mRemoteSDKStatusCallBack = remoteSDKStatusCallBack;
  47. }
  48. private int initService() {
  49. Log.d("mysdk", " sdk initService ");
  50. Intent intent = new Intent("com.example.androidsdkdemo.service.MySDKService");
  51. intent.setClassName("com.example.androidsdkdemo", "com.example.androidsdkdemo.service.MySDKService");
  52. isbind = mContext.bindService(intent, this, Service.BIND_AUTO_CREATE);
  53. return 0;
  54. }
  55. @Override
  56. public void setMessage(String msg) {
  57. try {
  58. Log.d("mysdk", " sdk setMessage ");
  59. mMyRemoteCtrl.sendMessage(msg);
  60. } catch (RemoteException e) {
  61. e.printStackTrace();
  62. }
  63. }
  64. @Override
  65. public void release() {
  66. Log.d("mysdk", " sdk release ");
  67. //SDK内部做释放操作
  68. }
  69. @Override
  70. public void onServiceConnected(ComponentName name, IBinder service) {
  71. Log.d("mysdk", " sdk onServiceConnected ");
  72. if (service == null) {
  73. if (mMyRemoteCtrl != null) {
  74. try {
  75. mMyRemoteCtrl.unlinkToDeath(mMySDKStatusCallBack.asBinder());
  76. } catch (RemoteException e) {
  77. e.printStackTrace();
  78. }
  79. }
  80. mMyRemoteCtrl = null;
  81. } else {
  82. mMyRemoteCtrl = MyRemoteCtrl.Stub.asInterface(service);
  83. if (mMyRemoteCtrl != null) {
  84. try {
  85. mMyRemoteCtrl.linkToDeath(mMySDKStatusCallBack.asBinder());
  86. } catch (RemoteException e) {
  87. e.printStackTrace();
  88. }
  89. try {
  90. mMyRemoteCtrl.registerMySDKStatusCallBack(mMySDKStatusCallBack);
  91. } catch (RemoteException e) {
  92. e.printStackTrace();
  93. }
  94. }
  95. }
  96. }
  97. @Override
  98. public void onServiceDisconnected(ComponentName name) {
  99. Log.d("mysdk", " sdk onServiceDisconnected ");
  100. if (mMyRemoteCtrl != null) {
  101. try {
  102. mMyRemoteCtrl.unregisterMySDKStatusCallBack(mMySDKStatusCallBack);
  103. mMyRemoteCtrl.unlinkToDeath(mMySDKStatusCallBack.asBinder());
  104. } catch (RemoteException e) {
  105. e.printStackTrace();
  106. }
  107. }
  108. mMyRemoteCtrl = null;
  109. }
  110. public static Controller getInstance() {
  111. if (mInstance == null) {
  112. synchronized (MyController.class) {
  113. if (mInstance == null) {
  114. mInstance = new MyController();
  115. }
  116. }
  117. }
  118. return mInstance;
  119. }
  120. }

MyController.java 里有一个 RemoteSDKStatusCallBack对象,这个对象是暴露给客户 让客户进行注册的类对象属于SDK自己的CallBack类,当客户端设置这个Callback之后 SDK中就持有了客户端实现的Callback对象实例, SDK在接收到 服务端的回调之后 可以通过RemoteSDKStatusCallBack 实例回调给客户.这样做有个好处,客户端不会持有服务端的代理对象和不会持有SDK中的AIDL的回调实例,SDK中实现的AIDL具体的Callback就对客户是不可见的,此处RemoteSDKStatusCallBack.java 内部的名字和MySDKStatusCallBack.aidl的相同,也可以根据自己的需求添加接口,或者修改名称.

  1. package com.example.mylibrary.callback;
  2. public interface RemoteSDKStatusCallBack {
  3. void statusCallBackVisible();
  4. void statusCallBackInvisible();
  5. void sendMessage(String message);
  6. }

之后进行进行生成jar包的配置,在mylibrary 的build.gradle 里面添加如下代码

注意 from('build/intermediates/aar_main_jar/debug/') 可能路径不同的版本不同需要搜索一下 classes.jar 路径 进行替换即可

  1. task makeJar(type:Copy){
  2. //如果之前存在,则先删除
  3. delete 'build/libs/mysdklib.jar'
  4. //设置拷贝的文件
  5. from('build/intermediates/aar_main_jar/debug/')
  6. //生成jar包后的文件目录位置
  7. into('build/libs/')
  8. //include,exclude参数来设置过滤
  9. include('classes.jar')
  10. //重命名
  11. rename('classes.jar','mysdklib.jar')
  12. }
  13. makeJar.dependsOn(build)

生成jar包的两种方式

  1,可以在根目录执行  ./gradlew makeJar

2.或者在右上角的 Gradle --> mylibrary-->Tasks --> other --> makeJar 双击makeJar 生成

到此 jar包的生成已经做完了.

 

第二步 : 写服务端的类 服务端app 

首先需要将 mylibrary 导入到app中,因为需要要到SDK中的aidl,在APP项目中的build.gradle 中的 dependencies 添加如下代码不然服务端使用不了mylibrary中的aidl文件.

implementation project(':mylibrary')

MySDKService.java 中的内部类 MyRemoteCtrlImpl 是服务的代理类 也是SDK端拿到的 MyRemoteCtrl代理对象类,服务中我们可以控制代理对象具体功能,那么也就间接的控制了第三方可以使用服务端app的那些功能,我们这里这里没有做具体的控制逻辑,只是将接收到的数据进行返回操作即可. 

  1. package com.example.androidsdkdemo.service;
  2. import android.app.Service;
  3. import android.content.Intent;
  4. import android.os.IBinder;
  5. import android.os.RemoteException;
  6. import android.util.Log;
  7. import androidx.annotation.Nullable;
  8. import com.example.mylibrary.MySDKStatusCallBack;
  9. import com.example.mylibrary.MyRemoteCtrl;
  10. public class MySDKService extends Service {
  11. private MyRemoteCtrlImpl mCarcorderRemoteCtrl = new MyRemoteCtrlImpl();
  12. private MySDKStatusCallBack mMySDKStatusCallBack = null;
  13. @Nullable
  14. @Override
  15. public IBinder onBind(Intent intent) {
  16. //返回内部代理对象给调用端
  17. return mCarcorderRemoteCtrl.asBinder();
  18. }
  19. public class MyRemoteCtrlImpl extends MyRemoteCtrl.Stub {
  20. private IBinder mBinder = null;
  21. private Object deathRecipient;
  22. @Override
  23. public void sendMessage(String msg) throws RemoteException {
  24. if (mMySDKStatusCallBack != null) {
  25. mMySDKStatusCallBack.sendMessage("我已经接收到你的数据返回给你 = " + msg);
  26. }
  27. }
  28. @Override
  29. public void linkToDeath(IBinder binder) throws RemoteException {
  30. Log.d("mysdk"," 服务端 建立死亡链接 ");
  31. mBinder = binder;
  32. binder.linkToDeath(mDeathRecipient, 0);
  33. }
  34. @Override
  35. public void unlinkToDeath(IBinder binder) throws RemoteException {
  36. Log.d("mysdk"," 服务端 断开客户端死亡链接 ");
  37. binder.unlinkToDeath(mDeathRecipient, 0);
  38. mBinder = null;
  39. }
  40. @Override
  41. public void registerMySDKStatusCallBack(MySDKStatusCallBack mySDKStatusCallBack) throws RemoteException {
  42. Log.d("mysdk"," 服务端 接收到 registerMySDKStatusCallBack ");
  43. mMySDKStatusCallBack = mySDKStatusCallBack;
  44. // mMySDKStatusCallBack 为第三方通过SDK传递过来的 对象 调用 mySDKStatusCallBack.statusCallBackInvisible()
  45. // 相当于持有 MySDKStatusCallBack mMySDKStatusCallBack
  46. //这里不做操作直接返回即可
  47. if (mMySDKStatusCallBack != null) {
  48. mySDKStatusCallBack.statusCallBackInvisible();
  49. }
  50. }
  51. @Override
  52. public void unregisterMySDKStatusCallBack(MySDKStatusCallBack mySDKStatusCallBack) throws RemoteException {
  53. Log.d("mysdk"," 服务端 接收到 unregisterMySDKStatusCallBack ");
  54. mMySDKStatusCallBack = null;
  55. }
  56. }
  57. IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
  58. @Override
  59. public void binderDied() {
  60. /* if (mMySDKStatusCallBack != null) {
  61. try {
  62. mMySDKStatusCallBack.statusCallBackInvisible();
  63. } catch (RemoteException e) {
  64. e.printStackTrace();
  65. }
  66. }*/
  67. //客户端可以执行释放操作
  68. Log.d("mysdk"," 调用端已经死亡");
  69. }
  70. };
  71. }

在AndroidManifest.xml中天机如下代码       android:enabled="true"   android:exported="true" 4.4 版本之后必须添加

  1. <service
  2. android:name="com.example.androidsdkdemo.service.MySDKService"
  3. android:enabled="true"
  4. android:exported="true">
  5. </service>

到此处服务端添加完成,此时可以运行一下服务端,先安装到手机上方便后期直接调用.

 

第三步:客户端 clienapp实现 

将mysdklib.jar 拷贝到 AndroidSDKDemo/clienapp/libs 下面 并且在 clienapp 项目 中 build.gradle的dependencies中

添加如下:

implementation files('libs/mysdklib.jar')

在 MainActivity 使用我们的sdk jar包中的类 MyLibSDK 进行服务端交互

  1. package com.example.clienapp;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.os.Bundle;
  4. import android.util.Log;
  5. import android.view.View;
  6. import com.example.mylibrary.MyLibSDK;
  7. import com.example.mylibrary.callback.RemoteSDKStatusCallBack;
  8. public class MainActivity extends AppCompatActivity {
  9. @Override
  10. protected void onCreate(Bundle savedInstanceState) {
  11. super.onCreate(savedInstanceState);
  12. setContentView(R.layout.activity_main);
  13. MyLibSDK.getInstance().init(this);
  14. MyLibSDK.getInstance().setStateCallback(new RemoteSDKStatusCallBack() {
  15. @Override
  16. public void statusCallBackVisible() {
  17. Log.d("mysdk"," 客户端 statusCallBackVisible ");
  18. }
  19. @Override
  20. public void statusCallBackInvisible() {
  21. Log.d("mysdk"," 客户端 statusCallBackInvisible ");
  22. }
  23. @Override
  24. public void sendMessage(String s) {
  25. Log.d("mysdk"," 客户端 sendMessage " + s);
  26. }
  27. });
  28. }
  29. public void sedmessage(View view) {
  30. Log.d("mysdk"," 客户端 sendMessage 我是客户端 " );
  31. MyLibSDK.getInstance().setMessage("我是客户端");
  32. }
  33. }

注意先运服务端再运行客户端 


运行结果如下:

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/265182
推荐阅读
相关标签
  

闽ICP备14008679号