Retrofit简单使用及混淆配置

Retrofit简介

什么是Retrofit?

官方解释:一个为Java和Android提供的类型安全的HTTP请求客户端

补充:Retrofit是 Square 公司开发的一个用于网络请求的开源库,内部封装了OkHttp,简化了我们的网络请求配置。

下面,附上官网链接方便各位查阅学习。

Retrofit使用实例

今天,Blogger用一个简单的实例来介绍下Retrofit的使用。

数据来源

使用的数据接口来自 GankIO(干货集中营)

数据接口链接: http://gank.io/api/data/数据类型/请求个数/第几页

  • 数据类型: 福利 | Android | iOS | 休息视频 | 拓展资源 | 前端 | all
  • 请求个数: 数字,大于0
  • 第几页:数字,大于0

接下来,我们想得到『福利』类型的第1页、前3条的数据,链接补全如下:

http://gank.io/api/data/福利/3/1

在浏览器打开链接后,我们可以看到数据的返回情况,如下图所示(红色文字是『截图注释』):

request_result.png

接下来我们要做的就是:在Android客户端使用Retrofit请求数据,之后用Log将数据打印出来(证明我们拿到数据了)。

Retrofit数据请求步骤

1. 添加Retrofit库。

在应用工程下的build.gradle文件中添加依赖库。

dependencies {
    
    ......

    // Retrofit
    compile 'com.squareup.retrofit2:retrofit:2.1.0'

    // Retrofit - Gson数据转换工具
    compile 'com.squareup.retrofit2:converter-gson:2.1.0'
}

2. 建立数据模型。

看到浏览器返回的数据,我们可以将数据层次分为两级,最外层为第一级,包含一个『数据反馈状态』和一个『数据列表』,额外添加toString()方法方便Log打印。(第一级数据模型如下所示):

/**
 * @ClassName: GankIOData
 * @Description: GankIO - 数据模型
 * @Author: wangnan7
 * @Date: 2016/12/30 下午5:27
 */
public class GankIOData implements Serializable {

    public boolean error;                  /* 数据是否出错 */
    public List<GankIOBaseData> results;   /* 数据列表 */

    @Override
    public String toString() {
        return "GankIOData{" +
                "error=" + error +
                ", results=" + results +
                '}';
    }
}

第二级数据模型是每条数据的详情信息,额外添加toString()方法方便Log打印,如下所示:

/**
 * @ClassName: GankIOBaseData
 * @Description: GankIO - 基本数据模型
 * @Author: wangnan7
 * @Date: 2016/12/30 下午5:29
 */
public class GankIOBaseData implements Serializable {

    public String _id;         /* 数据ID       (例:"_id": "5865ad4e421aa94dbe2ccdb0")*/
    public String createdAt;   /* 创建时间     (例:"createdAt": "2016-12-30T08:41:50.830Z")*/
    public String desc;        /* 描述         (例:"desc": "12-30") */
    public String publishedAt; /* 发布时间     (例:"publishedAt": "2016-12-30T16:16:11.125Z")*/
    public String source;      /* 来源         (例:"source": "chrome")*/
    public String type;        /* 类型         (例:"type": "\u798f\u5229")*/
    public String url;         /* 图片链接     (例:"url": "http://ww4.sinaimg.cn/large/610dc034jw1fb8iv9u08ij20u00u0tc7.jpg")*/
    public boolean used;       /* 是否被使用过  (例:"used": true)*/
    public String who;         /* 数据提供者    (例:"who": "daimajia")*/

    @Override
    public String toString() {
        return "GankIOBaseData{" +
                "_id='" + _id + '\'' +
                ", createdAt='" + createdAt + '\'' +
                ", desc='" + desc + '\'' +
                ", publishedAt='" + publishedAt + '\'' +
                ", source='" + source + '\'' +
                ", type='" + type + '\'' +
                ", url='" + url + '\'' +
                ", used=" + used +
                ", who='" + who + '\'' +
                '}';
    }
}

3. 建立服务接口。

我们将之前的接口链接(http ://gank.io/api/data/数据类型/请求个数/第几页)拆分为两部分:

  • 第1部分:http://gank.io/ (主机地址部分)
  • 第2部分:api/data/数据类型/请求个数/第几页 (路径及参数部分)

接下来,根据第2部分建立数据服务接口,代码如下:

/**
 * @ClassName: RetrofitService
 * @Description: 干货集中营 - 数据服务接口
 * @Author: wangnan7
 * @Date: 2016/12/30 下午5:40
 */
public interface RetrofitService {

    /**
     * 获取GankIO数据(http://gank.io/api/data/数据类型/请求个数/第几页)
     *
     * @param type  数据类型:福利 | Android | iOS | 休息视频 | 拓展资源 | 前端 | all
     * @param count 请求个数:数字,大于0
     * @param page  第几页:  数字,大于0
     */
    @GET("api/data/{type}/{count}/{page}")
    Call<GankIOData> getGankIOData(@Path("type") String type, @Path("count") int count, @Path("page") int page);

}

@GET:当前接口请求为Get请求。

@Path:路径补全。例:@Path("type") String type ,我们传入的type形参值会填入{type}中补全路径。

4. 构建Retrofit对象并请求接口数据。

在MainActivity中创建Retrofit对象并进行接口数据请求,代码如下:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Retrofit retrofit = new Retrofit.Builder() /* 创建一个Retrofit建造者 */
                .baseUrl("http://gank.io/") /* 传入请求接口的主机地址 */
                .addConverterFactory(GsonConverterFactory.create()) /* 添加Gson数据转换 */
                .build(); /* 建立Retrofit对象 */

        /* 创建服务接口实现类 */
        RetrofitService service = retrofit.create(RetrofitService.class);

        /* 补全接口请求参数,得到Call对象,执行完此步Retrofit的作用就已经完成了。(Call是Okhttp中的一个概念,代表了一个实际的HTTP请求) */
        Call<GankIOData> call = service.getGankIOData("福利", 3, 1);

        /* 请求网络,异步获取数据 */
        call.enqueue(new Callback<GankIOData>() {
            @Override
            public void onResponse(Call<GankIOData> call, Response<GankIOData> response) {
                if(response.isSuccessful()){ /* 检查返回的网络状态码是否在[200..300),一般200最为常见,300+表示请求的url被重定向了... */
                    GankIOData data =  response.body(); /* 获取数据模型 */
                    Log.e("TAG", data.toString()); /* 打印数据 */
                }
            }
            @Override
            public void onFailure(Call<GankIOData> call, Throwable t) {

            }
        });
    }
}

5. 添加联网权限。

不要忘记在AndroidManifest文件中添加联网权限手累,就不打三遍了O(∩_∩)O

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.testing.retrofitdemo">

    <!-- 联网权限 -->
    <uses-permission android:name="android.permission.INTERNET"/>
     
     ......
     
</manifest>

最后运行下程序,我们的Log工具就将数据打印出来了。

12-30 17:48:57.394 6915-6915/com.example.testing.retrofitdemo E/TAG: GankIOData{error=false, results=[GankIOBaseData{_id='5865ad4e421aa94dbe2ccdb0', createdAt='2016-12-30T08:41:50.830Z', desc='12-30', publishedAt='2016-12-30T16:16:11.125Z', source='chrome', type='福利', url='http://ww4.sinaimg.cn/large/610dc034jw1fb8iv9u08ij20u00u0tc7.jpg', used=true, who='daimajia'}, GankIOBaseData{_id='58645be0421aa94dbbd82bac', createdAt='2016-12-29T08:42:08.389Z', desc='12-29', publishedAt='2016-12-29T11:56:56.946Z', source='chrome', type='福利', url='http://ww4.sinaimg.cn/large/610dc034gw1fb7d9am05gj20u011hq64.jpg', used=true, who='daimajia'}, GankIOBaseData{_id='58632374421aa9723d29b9ba', createdAt='2016-12-28T10:29:08.507Z', desc='12-28', publishedAt='2016-12-28T11:57:39.616Z', source='chrome', type='福利', url='http://ww1.sinaimg.cn/large/610dc034gw1fb6aqccs3nj20u00u0wk4.jpg', used=true, who='daimajia'}]}

至此,我们的数据就请求成功了。

Retrofit混淆配置

我们一般在给应用打包上线时会给代码添加混淆配置,一来是为了防止别人反编译,二来是可以给apk文件瘦身

混淆开启方法,在应用工程下的build.gradle文件中,找到minifyEnabled配置项并设置为true,如下所示(注意这里是release配置,debug运行时混淆开关还是关着的):

android {

    ......
    
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

对于Retrofit,开启混淆开关后,我们还要在混淆文件(proguard-rules.pro)中添加一些混淆配置,在Retrofit官网中也有混淆的相关配置说明,如下所示:

如果你要在你的工程中使用混淆,需要添加以下几行配置项:

# Platform calls Class.forName on types which do not exist on Android to determine platform.
-dontnote retrofit2.Platform
# Platform used when running on RoboVM on iOS. Will not be used at runtime.
-dontnote retrofit2.Platform$IOS$MainThreadExecutor
# Platform used when running on Java 8 VMs. Will not be used at runtime.
-dontwarn retrofit2.Platform$Java8
# Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature
# Retain declared checked exceptions for use by a Proxy instance.
-keepattributes Exceptions

虽然官网给出了混淆配置,但还是想吐槽两句...

官网给的混淆配置其实并不完全,我们都知道Retrofit是对Okhttp的封装,Okhttp不需要添加混淆配置吗?另外,我们使用了Gson转换,Gson不需要添加混淆配置吗?还有,如果我们bean目录的数据模型的字段被混淆了,还能和服务端返回的数据对上吗?

  • 第一点:如果不添加Okhttp的混淆配置,编译到okio时会报错。
  • 第二点:此处Gson可以不添加混淆配置(这意味着Gson将会是混淆的)。
  • 第三点:要保证我们的数据模型不被混淆,否则得到的数据全是null。

最后,给各位列一下我的混淆文件中的相关配置:

# Retrofit
-dontnote retrofit2.Platform
-dontnote retrofit2.Platform$IOS$MainThreadExecutor
-dontwarn retrofit2.Platform$Java8
-keepattributes Signature
-keepattributes Exceptions

# okhttp
-dontwarn okio.**

# Gson
-keep class com.example.testing.retrofitdemo.bean.**{*;} # 自定义数据模型的bean目录

配置之后,打包混淆后的release版应用就能拿到数据了。

Retrofit进阶推荐

最后,给想要继续进阶Retrofit的小伙伴们推荐一篇博客:

【腾讯Bugly干货】深入浅出 Retrofit,这么牛逼的框架你们还不来看看?

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

推荐阅读更多精彩内容