分享好友 移动开发首页 频道列表

Android常用的开源项目及其比较系列-Retrofit进阶教程

Android开发  2016-12-01 14:320

上一篇我们谈了谈Androiod开源项目的网络框架, 比较了它们之间的优缺点,原文在 这里 。今天我们着重谈谈Retrofit框架如何更友好的使用,本着提出问题解决问题的原则,也为大家以后解决问题提供基本思路。

目前都有哪些问题?

根据官方Demo, 简单使用是这么样的

publicstaticGithubServicecreate(){

          Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
            return retrofit.create(GithubService.class);

        }

上面代码如果用在实际项目中有如下问题:

  • 只能创建指定的服务,而实际项目中可能有多种服务,如:登录,支付、事件上报、Github

  • URL固定,同样的实际项目中不同服务 base url可能不同。

  • 如果项目https中用到自签名证书该怎么办?

如何解决问题?

上面我们简单提出我们会遇到的问题, 其实总结就是一个问题 如何更好的封装Retrofit? 对于封装每个人的理解不一样,这就是为什么android中会出现那么多开源网络框架,我一直爱说“没有最好的、只有更好的”。

前面两个问题解决基本思路是首先我们提炼公共部分,然后实现不同的部分,,废话不多说先上代码。

public abstract classHttpClient{



    public static final String DEFAULT_API_BASE_URL = "https://api.github.com/";





    private static final Retrofit.Builder builder =

            new Retrofit.Builder().

            addConverterFactory(GsonConverterFactory.create());



    /**

     * 创建制定api服务

     * @param serviceClass

     * @param baseUrl

     * @param <T>

     * @return

     */

    protected <T> TcreateService(Class<T> serviceClass, String baseUrl){

        setApiBaseUrl(baseUrl);

        OkHttpClient client = OkHttpManager.getOkHttpClient(false);

        Retrofit retrofit = builder.client(client).build();

        return retrofit.create(serviceClass);

    }

    /**

     * 设置base url

     */

    privatevoidsetApiBaseUrl(String baseUrl){

        String apiBaseUrl = baseUrl == null ? DEFAULT_API_BASE_URL : baseUrl;

        builder.baseUrl(apiBaseUrl);

    }

}

从上面的代码我们可以看到创建一个createService抽象方法,让子类进行相应的实现。代码如下:

publicGithubHttpService(){

    mService = createService(GithubAPIService.class, PAY_API_BASE_URL);

}

如何解决自签名问题?

解决签名问题之前,我们来说说什么是自签名?因为Retrofit访问网络是通过okhttp去真正进行网络请求的, 而okhttp默认情况下是支持https协议的,比如: https://www.google.com、https://www.github.com。支持的https的网站基本都是CA机构颁发的证书,默认情况下是可以信任的。

当自己搭建https的网站,自己通过keytool去生成一个证书,然后使用,并不是CA机构去颁发的。使用自签名证书的网站,大家在使用浏览器访问的时候,一般都是报风险警告,大名鼎鼎的网站就是这么干的,12306。

如果通过代码访问,可能有如下异常:


javax.net.ssl.SSLHandshakeException: 
    java.security.cert.CertPathValidatorException: 
        Trust anchor for certification path not found.javax.net.ssl.SSLHandshakeException:

简单说一下, https协议其实是http+SSL, SSL位于TCP/IP和HTTP协议之间,最终保证数据安全。客服端和服务端建立连接之前需要,先要进行一次握手,基本原理如下:

  1. 浏览器将自己支持的一套加密算法、HASH算法发送给网站。
  1. 网站从中选出一组加密算法与HASH算法,并将自己的身份信息以证书的形式发回给浏览器。证书里面包含了网站地址,加密公钥,以及证书的颁发机构等信息。

  2. 浏览器获得网站证书之后,开始验证证书的合法性,如果证书信任,则生成一串随机数字作为通讯过程中对称加密的秘钥。然后取出证书中的公钥,将这串数字以及HASH的结果进行加密,然后发给网站。

  3. 网站接收浏览器发来的数据之后,通过私钥进行解密,然后HASH校验,如果一致,则使用浏览器发来的数字串使加密一段握手消息发给浏览器。
  4. 浏览器解密,并HASH校验,没有问题,则握手结束。接下来的传输过程将由之前浏览器生成的随机密码并利用对称加密算法进行加密。

代码实现如下:


publicstaticSSLParamsgetSslSocketFactory(InputStream[] certificates, InputStream bksFile, String password){

        SSLParams sslParams = new SSLParams();

        try {

            TrustManager[] trustManagers = prepareTrustManager(certificates);

            KeyManager[] keyManagers = prepareKeyManager(bksFile, password);

            SSLContext sslContext = SSLContext.getInstance("TLS");

            X509TrustManager trustManager;

            if (trustManagers != null) {

                trustManager = new MyTrustManager(chooseTrustManager(trustManagers));

            } else {

                trustManager = new UnSafeTrustManager();

            }

            sslContext.init(keyManagers, new TrustManager[]{trustManager}, null);

            sslParams.sSLSocketFactory = sslContext.getSocketFactory();

            sslParams.trustManager = trustManager;

            return sslParams;

        } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {

            throw new Assertion
Error(e);

        }

    }

上面代码主要干了上面几件事

  • 构造CertificateFactory对象,通过它的generateCertificate(is)方法得到Certificate。

  • 然后讲得到的Certificate放入到keyStore中。

  • 通过trustManagers、keyManagers初始化我们的SSLContext

调用如下:


privatevoidsetHttpBuilderSSLParams(){

        //设置自签名证书相关参数

// InputStream[] certificates = {new Buffer().writeUtf8(CER_TEST).inputStream()};

        HttpsUtils.SSLParams sslParams = HttpsUtils.getSslSocketFactory(null, null, null);

        httpBuilder.hostnameVerifier(new HttpsUtils.UnSafeHostnameVerifier())

                .sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager);

    }

如果是单向认证,上面就可以了, 如果是双向的,即服务端要认证客服端的合法性,HttpsUtils.getSslSocketFactory(null, null, null) 后两个参数就是要填client的bsf文件和相应的密码了,一般用在安全性比较高的场景,如:支付。

总结

好了, 到目前为止我们已经解决上面所提到的问题了, 这里只是Call使用, 还可以结合RxJava一块使用, 可以让威力变得无穷。

如果你有更好的想法, 可以联系我,一块探讨、进步!

项目地址: GitHub

查看更多关于【Android开发】的文章

展开全文
相关推荐
反对 0
举报 0
评论 0
图文资讯
热门推荐
优选好物
更多热点专题
更多推荐文章
[Java] Retrofit2.0 如何进行GBK编码
对Retrofit + OkHttp还不熟悉的人可以点传送门,先看下这两个东西的使用。Retrofit:https://github.com/square/retrofitOkHttp:https://github.com/square/okhttp分析接口文档要求Post请求,字段使用GBK编码我们先按照Retrofit的规范和接口文档来写接口: @PO

0评论2016-12-231093

从 Retrofit 源码学习 Java 的动态代理的使用
Retrofit 是当前 Android 最流行的 HTTP 网络库之一了,其使用方式比较特殊,是通过定义一个接口类,通过给接口中方法和方法参数添加注解的方式来定义网络请求接口。这种风格下定义一个网络接口变得很简单。不过 Retrofit 是如何使用一个接口的 Class 创建出

0评论2016-11-13181

Android Retrofit框架解析
随着Google对HttpClient的摒弃,和Volley的逐渐没落,OkHttp开始异军突起,而Retrofit则对okHttp进行了强制依赖。Retrofit也是Square公司开发的一款针对Android网络请求的框架,其实质就是对okHttp的封装,使用面向接口的方式进行网络请求,利用动态生成的代理类

0评论2016-10-04120

Android网络开源库-Retrofit(五)简易封装
1.前言Rrtrofit的扩展性很强,如果对retrofit不熟悉的话,是很难应对各种各样的需求的。因此,在这里,做一下简单的封装。主要为了下面三点需求:使用简单加密处理错误处理2.怎样才能简单使用为了简单粗暴,我做了以下工作。使用单例Retrofit引入RxJava在这里

0评论2016-10-04161

Android网络开源库-Retrofit(四)文件相关
以前写过一些retrofit的相关文章,当时只是自己学习研究的,最近项目,加入了retrofit,因此遇到了一些问题,需要记录一下。1.前言在以前,写过retrofit上传文件相关,但是,需求总是变化的。前面的,介绍了上传进度的监听,但是,那时候是监听单文件进度。虽

0评论2016-10-04248

急速开发系列——Retrofit 响应数据及异常处理策略
今天我们来谈谈客户端对通讯协议的处理,主要分为三部分:约定响应数据格式,响应数据的自动映射以及错误处理三部分。由于数据协议采用json的居多,因此我们在此基础上进行说明。约定响应数据格式协议格式通常来说,你拿到的设计文档中会存在通信协议的说明,

0评论2016-09-29129

更多推荐