Android使用OkHttp与https通讯及下载更新APP - Go语言中文社区

Android使用OkHttp与https通讯及下载更新APP


最近公司项目要求APP客户端与服务端通讯时经过https协议,但是初次搭的https环境没有安全的数字证书,是JDK生成的证书,APP访问过程中遇到了一些问题。

报了一个这样的错

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

百度了一下是数字证书的问题,但是我的客户端请求框架是OkHttp

原先用的是

'com.ansen.http:okhttpencapsulation:1.0.1'

这个框架去做请求以及下载文件的

主要用到的类HTTPCaller.java的源码当中,可以看到它对OkHttp的使用

	/**
	 * 设置配置信息 这个方法必需要调用一次
	 * @param httpConfig
     */
	public void setHttpConfig(HttpConfig httpConfig) {
		this.httpConfig = httpConfig;

		client = new OkHttpClient.Builder()
				.connectTimeout(httpConfig.getConnectTimeout(), TimeUnit.SECONDS)
				.writeTimeout(httpConfig.getWriteTimeout(), TimeUnit.SECONDS)
				.readTimeout(httpConfig.getReadTimeout(), TimeUnit.SECONDS)
				.build();

		gson = new Gson();
		requestHandleMap = Collections.synchronizedMap(new WeakHashMap<String, Call>());
		cacheControl =new CacheControl.Builder().noStore().noCache().build();//不使用缓存
	}

通过HttpConfig类去设置配置信息,然后好像没法直接屏蔽验证数字证书

最后我决定直接用OkHttp,使用方法参考了一下两篇文章~

https://www.cnblogs.com/maomishen/p/5403301.html

https://www.jb51.net/article/117675.htm

工具类OkHttpUtil.java

package com.gotop.sanqinapp.util;

import java.io.IOException;
import java.lang.reflect.Field;
import java.security.SecureRandom;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import okhttp3.Callback;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * @Author:Swallow
 * @Date:2019/7/4
 **/
public class OkHttpUtil {

    private static OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(20*1000, TimeUnit.MILLISECONDS)
            .readTimeout(20*1000,TimeUnit.MILLISECONDS)
            .writeTimeout(20*1000,TimeUnit.MILLISECONDS).build();

//绕开数字证书的方法
    public static void setHttpConfig() {
        SSLContext sc = null;
        try {
            sc = SSLContext.getInstance("SSL");
            sc.init(null, new TrustManager[]{new X509TrustManager() {
                @Override
                public void checkClientTrusted(
                        java.security.cert.X509Certificate[] chain, String authType)
                        throws java.security.cert.CertificateException {

                }
                @Override
                public void checkServerTrusted(
                        java.security.cert.X509Certificate[] chain, String authType)
                        throws java.security.cert.CertificateException {

                }

                @Override
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            }}, new SecureRandom());

        } catch (Exception e) {
            e.printStackTrace();
        }
        HostnameVerifier hv1 = new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };
        String workerClassName="okhttp3.OkHttpClient";
        try {
            Class workerClass = Class.forName(workerClassName);
            Field hostnameVerifier = workerClass.getDeclaredField("hostnameVerifier");
            hostnameVerifier.setAccessible(true);
            hostnameVerifier.set(client, hv1);
            Field sslSocketFactory = workerClass.getDeclaredField("sslSocketFactory");
            sslSocketFactory.setAccessible(true);
            sslSocketFactory.set(client, sc.getSocketFactory());
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    public static String sendGetSSL(Map<String, String> map, String url) throws IOException {

        setHttpConfig();
        String result = "";
        StringBuilder reqUrl = new StringBuilder(url);
        if (map != null && map.size() > 0) {
            reqUrl.append("?");
            for (Map.Entry<String, String> param : map.entrySet()) {
                reqUrl.append(param.getKey() + "=" + param.getValue() + "&");

            }
            url = reqUrl.subSequence(0, reqUrl.length() - 1).toString();
        }

        Request request = new Request.Builder()
                .url(url)
                .get()
                .build();
        try (Response response = client.newCall(request).execute()) {
            result = response.body().string();
        }
        return result;
    }

    public static void downloadFile(String url, final ProgressListener listener, Callback callback){

        setHttpConfig();

        OkHttpClient okHttpClient = client.newBuilder().addNetworkInterceptor(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Response response = chain.proceed(chain.request());
                return response.newBuilder().body(new ProgressResponseBody(response.body(),listener)).build();
            }
        }).build();

        Request request  = new Request.Builder().url(url).build();
        okHttpClient.newCall(request).enqueue(callback);
    }

}

下载更新apk

    /**
     * 开始下载
     * @param downloadUrl 下载url
     * @param context 当前context
     */
    public static void startUpload(String downloadUrl, final Context context){
        //显示进度条对话框
        progressDialog=new ProgressDialog(context);
        progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        progressDialog.setMessage("正在下载新版本");
        progressDialog.setCancelable(false);//不能手动取消下载进度对话框
        final String fileSavePath=Utils.getSaveFilePath(downloadUrl);
        //下载文件并且显示进度条
        OkHttpUtil.downloadFile(downloadUrl, new ProgressListener() {
            @Override
            public void onProgress(long currentBytes, long contentLength, boolean done) {
                //文件最大长度
                progressDialog.setMax((int)contentLength);
                //已下载进度
                progressDialog.setProgress((int)currentBytes);
                progressDialog.show();
                if(done) {
                    openAPK(fileSavePath,context);
                }
            }
        }, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }


            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response != null) {
                    InputStream is = response.body().byteStream();
                    FileOutputStream fos = new FileOutputStream(fileSavePath);
                    int len = 0;
                    byte[] buffer = new byte[2048];
                    while (-1 != (len = is.read(buffer))) {
                        fos.write(buffer, 0, len);
                    }
                    fos.flush();
                    fos.close();
                    is.close();
                }
            }
        });
    }
    /**
     * 下载完成安装apk
     * @param fileSavePath
     */
    private static void openAPK(String fileSavePath, Context context){
        File file=new File(fileSavePath);
        Intent intent = new Intent(Intent.ACTION_VIEW);
        Uri data;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            data = FileProvider.getUriForFile(context, "com.gotop.sanqinapp.fileprovider", file);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);// 给目标应用一个临时授权
        } else {
            data = Uri.fromFile(file);
        }
        intent.setDataAndType(data, "application/vnd.android.package-archive");
        context.startActivity(intent);
    }

更新过程当中会遇到权限问题,AndroidManifest.xml文件中加入

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

安卓6.0以上需要动态获取权限,使用方法可以参考这里

最后,问题解决,能够访问https并且下载文件,更新版本,显示进度条,yes

 

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/FRYAN28/article/details/101532619
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-05-16 12:52:49
  • 阅读 ( 1700 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

推荐文章

猜你喜欢