前言
相信很多同学都知道鸿神的WanAndroidapi,也写过很多酷炫的App,flutter、compose、kotlin、Java、小程序等各种版本,但是写过sdk的很少,sdk开发很常见,比如直播sdk、美颜sdk、统计sdk等等,本系列博客会有4-6篇,从sdk初始化、sdk开发、sdk合并、sdk文档编写等一步步慢慢讲解,看完之后,我相信各位同学都会开发属于自己的sdk.本篇是第一篇利用第三方库实现自己的sdk开发。
其实之前有写个2篇关于sdk开发的文章,有兴趣的同学可以去看看,博客地址如下:
Android SDK开发1将完整项目或Module打包成aar_u012556114的博客-CSDN博客
AndroidSDK开发2SDK初始化问题_u012556114的博客-CSDN博客_android sdk 初始化
思路:
1.封装一个初始化管理工具类便于交互.
2.根据需求封装相应的接口和请求,以接口形式给出请求参数和返回结果.
3.本篇采用依赖第三方库请求的方式来写sdk.
实现
一、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配置如下:
完整配置代码:
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')
}
3.sdk初始化:
private void initWanSdk() {
App.setApp(MyApplication.getInstance());
}
4.调用首页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;
}
});
}
测试结果如下,可以看到结果正常返回,打印出想要的数据:
七、总结一下:
本篇文章其实去年就写好了,只是不知道以啥样的形式展现出来,再加上工作原因,而我本人又变懒惰了,文章的构思和排版不是很好,所以最近才发布,花费了近3个多小时终于是完成了。
这里sdk开发首先是初始化,然后是接口设计,打包成aar,当然还有文档编写,sdk加密,sdk中aar的合并,本文是这系列的第一篇,小伙伴可以直接尝试一下,里面的代码不重要,这里都是写的很粗糙,由于是演示demo,大家可以根据自己的习惯来写,主要学习一下思想和怎么写成一个sdk的过程,这里也没有把aar放到远程仓库,直接本地引用的,有兴趣的同学可以放到自己的远程仓库,本文肯定有很多不足之处,希望大家谅解,有问题提出来我及时更正,一起学习进步.
wanandroidsdkdemo的源码地址如下:
WanAndroidSdk: 利用鸿神的wanAndroid开源APi封装的wanAndroidsdk,可以快速调用
我的csdn地址:
https://blog.csdn.net/u012556114
原创不易,如需转载请说明出处!!