我用玩AndroidApi写了一个sdk

 前言

相信很多同学都知道鸿神的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

原创不易,如需转载请说明出处!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容