前言
相信很多同学都知道鸿神的WanAndroidapi,也写过很多酷炫的App,flutter、compose、kotlin、Java、小程序等各种版本,但是写过sdk的很少,sdk开发很常见,比如直播sdk、美颜sdk、统计sdk等等,本系列博客会有4-6篇,从sdk初始化、sdk开发、sdk合并、sdk文档编写等一步步慢慢讲解,看完之后,我相信各位同学都会开发属于自己的sdk.本篇是第一篇利用第三方库实现自己的sdk开发。
1.其实之前有写个2篇关于sdk开发的文章,有兴趣的同学可以去看看,博客地址如下:
Android SDK开发1将完整项目或Module打包成aar_u012556114的博客-CSDN博客
AndroidSDK开发2SDK初始化问题u012556114的博客-CSDN博客android sdk 初始化
2.思路:
2.1封装一个初始化管理工具类便于交互.
2.2根据需求封装相应的接口和请求,以接口形式给出请求参数和返回结果.
2.3本篇采用依赖第三方库请求的方式来写sdk.
一.实现
1.sdk初始化:对内方便管理,对外提供一个接口或者方法
1.在Application中写一个设置值和返回的方法 public class App extends Application { private static Application mInstance; @Override public void onCreate() { super.onCreate(); mInstance = this; } public static void setApp(Application app){ mInstance = app; } public static Application getInstance() { return mInstance; } }
2.封装一个初始化管理类:
/** *@author: njb *@date: 2021/2/23 17:11 *@desc: 交互工具类 */ public class WanAndroidManager { var mContext: Context? = null fun init(application: Application){ mContext =application.applicationContext } }
二、网络请求:
包含WanAndroidHttpUtil、api、BaseApi、APIService、WanAndroidHttpResult五个类.
1.封装一个网络请求工具类:WanAndroidHttpUtil,可以看到这里的网络请求都是以接口形式回调出来.
/** * @author: njb * @date: 2021/2/23 17:55 * @desc: 网络请求工具类 */ public class WanAndroidHttpUtil { public static void getBanner(final BannerCallBack callBack) { (Api.getDefault().banner()).enqueue(new Callback<WanAndroidHttpResult<List<BannerBean>>>() { @Override public void onResponse(@NotNull Call<WanAndroidHttpResult<List<BannerBean>>> call, @NotNull Response<WanAndroidHttpResult<List<BannerBean>>> response) { WanAndroidHttpResult<List<BannerBean>> result = response.body(); if (result != null && result.isBizSucceed(true) && result.getData() != null) { callBack.onResponse(result); } } @Override public void onFailure(@NotNull Call<WanAndroidHttpResult<List<BannerBean>>> call, @NotNull Throwable t) { callBack.onFailure(t.getMessage()); } }); } public static void getArticle(int page, final ArticleCallBack callBack) { Api.getDefault().articleList(page).enqueue(new Callback<WanAndroidHttpResult<ArticleListBean>>() { @Override public void onResponse(Call<WanAndroidHttpResult<ArticleListBean>> call, Response<WanAndroidHttpResult<ArticleListBean>> response) { WanAndroidHttpResult<ArticleListBean> result = response.body(); if (result != null && result.isBizSucceed(true) && result.getData() != null) { callBack.onResponse(result); } } @Override public void onFailure(Call<WanAndroidHttpResult<ArticleListBean>> call, Throwable t) { callBack.onFailure(t.getMessage()); } }); } public static void getHotKey(final HotKeyCallBack callBack){ Api.getDefault().getHotKey().enqueue(new Callback<WanAndroidHttpResult<List<HotKeyBean>>>() { @Override public void onResponse(@NotNull Call<WanAndroidHttpResult<List<HotKeyBean>>> call, @NotNull Response<WanAndroidHttpResult<List<HotKeyBean>>> response) { WanAndroidHttpResult<List<HotKeyBean>> result =response.body(); if (result != null && result.isBizSucceed(true) && result.getData() != null) { callBack.onResponse(result); } } @Override public void onFailure(@NotNull Call<WanAndroidHttpResult<List<HotKeyBean>>> call, @NotNull Throwable t) { callBack.onFailure(t.getMessage()); } }); } public static void getKnwLedge(final KnowLedgeCallBack callBack){ Api.getDefault().getKnowLedge().enqueue(new Callback<WanAndroidHttpResult<List<KnowledgeBean.DataBean>>>() { @Override public void onResponse(@NotNull Call<WanAndroidHttpResult<List<KnowledgeBean.DataBean>>> call, @NotNull Response<WanAndroidHttpResult<List<KnowledgeBean.DataBean>>> response) { WanAndroidHttpResult<List<KnowledgeBean.DataBean>> result = response.body(); if (result != null && result.isBizSucceed(true) && result.getData() != null) { callBack.onResponse(result); } } @Override public void onFailure(@NotNull Call<WanAndroidHttpResult<List<KnowledgeBean.DataBean>>> call, @NotNull Throwable t) { callBack.onFailure(t.getMessage()); } }); } public interface BannerCallBack { BannerBean onResponse(WanAndroidHttpResult<List<BannerBean>> beanEduHttpResult); BannerBean onFailure(String message); } public interface ArticleCallBack { ArticleListBean onResponse(WanAndroidHttpResult<ArticleListBean> androidHttpResult); ArticleListBean onFailure(String message); } public interface HotKeyCallBack{ HotKeyBean onResponse(WanAndroidHttpResult<List<HotKeyBean>> androidHttpResult); HotKeyBean onFailure(String message); } public interface KnowLedgeCallBack{ KnowledgeBean.DataBean onResponse(WanAndroidHttpResult<List<KnowledgeBean.DataBean>> wanAndroidHttpResult); String onFailure(String message); } }
2.网络请求Api:
public class Api extends BaseApi { private static ApiService SERVICE; public static ApiService getDefault() { if (SERVICE == null) { //获取请求客户端 OkHttpClient.Builder httpClientBuilder = getHttpClient(Api.class.getSimpleName()); SERVICE = new Retrofit.Builder() .client(httpClientBuilder.build()) .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .baseUrl(Constants.EasyPlayHostDefault) .build().create(ApiService.class); } return SERVICE; } }
3.BaseApi:
public class BaseApi { public static final int DEFAULT_TIMEOUT = 20000;//10秒 protected static OkHttpClient.Builder getHttpClient(final String tagName) { OkHttpClient.Builder httpClientBuilder; //设置缓存路径,系统默认缓存路径,并且限制缓存大小500m Cache cache = new Cache(new File(Objects.requireNonNull(App.getInstance()).getCacheDir(), "HttpCache"), 500); httpClientBuilder = new OkHttpClient.Builder().cache(cache); try { httpClientBuilder.addNetworkInterceptor(new HeaderInterceptor()); httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); httpClientBuilder.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); httpClientBuilder.readTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); httpClientBuilder.retryOnConnectionFailure(true); //根据当前调试状态,是否显示请求日志 if (BuildConfig.DEBUG) { HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() { @Override public void log(String message) { LogUtils.e(tagName + "", message); } }); interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); httpClientBuilder.addInterceptor(interceptor); httpClientBuilder.addInterceptor(new CustomLoggingInterceptor()); } } catch (Exception e) { e.printStackTrace(); } return httpClientBuilder; } static class CustomLoggingInterceptor implements Interceptor { private String TAG = BaseApi.class.getSimpleName(); @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); return chain.proceed(request); } } }
4.ApiService:
/** * @author: njb * @date: 2021/2/24 18:04 * @desc: */ public interface ApiService { /** * 获取首页banner */ @GET(Constants.BANNER_LIST) Call<WanAndroidHttpResult<List<BannerBean>>> banner(); /** * 获取文章列表 * @param page * @return */ @GET(Constants.ARTICLE_LIST) Call<WanAndroidHttpResult<ArticleListBean>> articleList(@Path("page") int page); /** *获取搜索热词 * * * */ @GET(Constants.HOT_KEY) Call<WanAndroidHttpResult<List<HotKeyBean>>> getHotKey(); /** * 获取知识 * @return */ @GET(Constants.TREE) Call<WanAndroidHttpResult<List<KnowledgeBean.DataBean>>> getKnowLedge(); }
5.WanAndroidHttpResult:请求结果类
/** * @author: njb * @date: 2021/2/23 17:32 * @desc: */ public class WanAndroidHttpResult<T> { /** * 记录请求回来的状态描述 */ private String errorMsg; /** * 记录请求回来的错误状态描述 */ private String code = ""; /** * 记录请求回来的错误状态描述 */ private Integer errorCode = 0; /** * 记录返回的数据 */ private T data; /** * 业务是否成功 */ public boolean isBizSucceed(boolean defaultValue) { return null == errorCode ? defaultValue : errorCode == 0; } public void setMessage(String message) { this.errorMsg = message; } public T getData() { return data; } public void setData(T data) { this.data = data; } }
三、导入的第三方库:
//rxjava implementation 'io.reactivex.rxjava2:rxjava:2.2.12' implementation 'com.squareup.retrofit2:retrofit:2.6.2' implementation 'com.squareup.retrofit2:adapter-rxjava2:2.6.0' implementation 'com.squareup.retrofit2:converter-scalars:2.4.0' implementation 'com.squareup.retrofit2:converter-gson:2.6.2' implementation 'com.squareup.okhttp3:okhttp:4.2.0' implementation 'com.squareup.okhttp3:logging-interceptor:3.6.0' implementation 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle:2.2.2'
四、build.gradle和Manifest配置:
1.build,gradle配置:
//apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'com.android.library'
2.Manifest配置:
<uses-permission android:name="android.permission.INTERNET"/> <application android:allowBackup="true"> </application>
五、打包成aar,截图依次如下5-1、5-2、5-3:
第1步把build.gradle的
apply plugin: 'com.android.application改为apply plugin: 'com.android.library'
第2步把applicationId注释
第3步把Manifest里面application的theme、图标全部去掉,只保留
android:allowBackup="true"
第4步点开Studio右边的Gradle按钮,可以看到如下图的选项,选择assemable
第5步点开项目App的-----build------outputs----aar目录,看到生成的aar文件,有debug和release两个.
图5-1
图5-2
图5-3
如果有不会的或者看不明白的同学可以看我之前的博客,里面有详细步骤,这里就不展开讲解,把项目或者module打包成aar的博客地址如下:
Android SDK开发1将完整项目或Module打包成aar_u012556114的博客-CSDN博客
六、在新项目中的使用,这里新建一个项目WanAndroidSdkTest:
引入项目步骤如下:
1.把打包好的aar放到项目的libs目录下,这里命名为:wanandroidsdk_v1.0.0
2.build.gradle配置如下:
3.完整配置代码:
plugins { id 'com.android.application' id 'kotlin-android' } android { compileSdkVersion 28 buildToolsVersion "28.0.3" defaultConfig { applicationId "com.example.wanandroidsdktest" minSdkVersion 19 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } repositories { //libs 目录 flatDir { dirs "libs" } } } dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation 'androidx.core:core-ktx:1.6.0' implementation 'androidx.appcompat:appcompat:1.3.1' implementation 'com.google.android.material:material:1.4.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.1' testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' //rxjava implementation 'io.reactivex.rxjava2:rxjava:2.2.12' implementation 'com.squareup.retrofit2:retrofit:2.6.2' implementation 'com.squareup.retrofit2:adapter-rxjava2:2.6.0' implementation 'com.squareup.retrofit2:converter-scalars:2.4.0' implementation 'com.squareup.retrofit2:converter-gson:2.6.2' implementation 'com.squareup.okhttp3:okhttp:4.2.0' implementation 'com.squareup.okhttp3:logging-interceptor:3.6.0' implementation 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle:2.2.2' implementation(name: 'wanandroidsdk_v1.0.0', ext: 'aar') }
4.sdk初始化:
private void initWanSdk() { App.setApp(MyApplication.getInstance()); }
5.调用首页banner、文章列表、搜索热词、知识列表接口:
private void initData() { //获取首页Banner getBanner(); //获取文章列表 initArticle(); //获取热门关键字 initHotKey(); //获取知识列表 initKnowledge(); } private void getBanner() { WanAndroidHttpUtil.getBanner(new WanAndroidHttpUtil.BannerCallBack() { @Override public BannerBean onResponse(WanAndroidHttpResult<List<BannerBean>> wanAndroidHttpResult) { LogUtils.d("--BannerData--", wanAndroidHttpResult.getData().toString()); return null; } @Override public BannerBean onFailure(String message) { LogUtils.d("message", message); return null; } }); } private void initArticle() { WanAndroidHttpUtil.getArticle(1, new WanAndroidHttpUtil.ArticleCallBack() { @Override public ArticleListBean onResponse(WanAndroidHttpResult<ArticleListBean> wanAndroidHttpResult) { LogUtils.d("--ArticleData--", wanAndroidHttpResult.getData().toString()); return null; } @Override public ArticleListBean onFailure(String message) { LogUtils.d("message", message); return null; } }); } private void initHotKey() { WanAndroidHttpUtil.getHotKey(new WanAndroidHttpUtil.HotKeyCallBack() { @Override public HotKeyBean onResponse(WanAndroidHttpResult<List<HotKeyBean>> wanAndroidHttpResult) { LogUtils.d("--hotData--", wanAndroidHttpResult.getData().toString()); return null; } @Override public HotKeyBean onFailure(String message) { LogUtils.d("message", message); return null; } }); } private void initKnowledge() { WanAndroidHttpUtil.getKnwLedge(new WanAndroidHttpUtil.KnowLedgeCallBack() { @Override public KnowledgeBean.DataBean onResponse(WanAndroidHttpResult<List<KnowledgeBean.DataBean>> wanAndroidHttpResult) { LogUtils.d("--KnowData--", wanAndroidHttpResult.getData().toString()); return null; } @Override public String onFailure(String message) { LogUtils.d("message", message); return null; } }); }
6.测试结果如下,可以看到结果正常返回,打印出想要的数据:
7.总结一下:
本篇文章其实去年就写好了,只是不知道以啥样的形式展现出来,再加上工作原因,而我本人又变懒惰了,文章的构思和排版不是很好,所以最近才发布,花费了近3个多小时终于是完成了。
这里sdk开发首先是初始化,然后是接口设计,打包成aar,当然还有文档编写,sdk加密,sdk中aar的合并,本文是这系列的第一篇,小伙伴可以直接尝试一下,里面的代码不重要,这里都是写的很粗糙,由于是演示demo,大家可以根据自己的习惯来写,主要学习一下思想和怎么写成一个sdk的过程,这里也没有把aar放到远程仓库,直接本地引用的,有兴趣的同学可以放到自己的远程仓库,本文肯定有很多不足之处,希望大家谅解,有问题提出来我及时更正,一起学习进步.
8.wanandroidsdkdemo的源码地址如下:
WanAndroidSdk: 利用鸿神的wanAndroid开源APi封装的wanAndroidsdk,可以快速调用
原创不易,如需转载请说明出处!!