Android 使用https 协议请求客户端

server端操作

  • 自己创建 CA 证书

  • 拿自建CA 证书创建 server 端证书

  • 创建 https 服务

Android客户端操作

  • 创建项目并引入相关依赖

  • 生成 Android端 keystore

  • MainActivity.java & 布局文件 activity_main.xml

  • 修改 Android 模拟器的 hosts 文件

  • Android 端发送HTTPS 请求进行验证

本文 Android 端 DEMO案例 下载

https://github.com/Jxyxl259/android-https_demo/tree/master/app

Volley 官方git地址(需要vans——"off the wall")

https://android.googlesource.com/platform/frameworks/volley

参考链接:

【Android】Volley的Https请求

der pem cer crt key pfx等概念及区别

java证书以及证书管理

Android网络安全配置官方文档


写在开头:

最近在自学Android ,记得17年 也就是H5火起来的时候,听说很多培训机构都不再开设Android培训班了,因为没钱赚,培训出来的学生也不好找工作,弄不好还砸了自己培训班的口碑。

随后再想入门安卓的人,只有自学这一条路。这就导致一个现象, 安卓开发人员两级分化太严重,要么就是搞了三五年甚至年限更久经验丰富的developer,要么就是刚入行没人带,只能自己一点点踩坑积累经验的菜鸡。

而且网上能找到的 Android的自学资料简直太少太老,也可能是我比较懒,找到一份资料就开始看,懒得再去找其他资料。

BUT!

Android 的项目目录结构是真花哨(相比java 而言)而且还用的gradle 编译项目,无奈之下 把gradle 也学了一遍,在此由衷的感谢 runoob.com

AND!

Android 的各个SDK 版本之间的差别大了去了,做版本兼容什么的着实叫人头大

正题:

server端操作

  • 自己创建 CA 证书(这里以 nodejs 搭建 https 服务为例)

在用户目录下创建 my_ca目录
~ ] $ mkdir myCA
进入my_ca 目录,依次执行下面指令(都有注释) 生成 CA 证书请求 最后的密码(change password) 以及 optional company name 可以不用填 直接回车跳过

openssl genrsa -des3 -out ica.key 1024
openssl req -new -key ica.key -out ssl.csr
sudo openssl x509 -req -in ssl.csr -extensions v3_ca -signkey ica.key -out ica.crt
  • 拿自建CA 证书创建 server 端证书

在用户目录下创建 myCA目录
~ ] $ mkdir myCA
进入myCA 目录,依次执行下面指令(都有注释) 生成 CA 证书请求 最后的密码(change password) 以及 optional company name 可以不用填 直接回车跳过
openssl genrsa -out server.key 1028
openssl req -new -key server.key -out server.csr

生成server端 根证书,在 myCA 目录下编辑一个 opsnssl.cnf

~/myCA ] $ vim opsnssl.cnf
[req]distinguished_name = req_distinguished_namereq_extensions = v3_req[req_distinguished_name]countryName = CNcountryName_default = CNstateOrProvinceName = BJstateOrProvinceName_default = BJlocalityName = BeijinglocalityName_default = BeijingorganizationalUnitName  = 组织名称(随便填)organizationalUnitName_default = 默认组织名称(随便填)commonName = helloworld.comcommonName_max  = 64[ v3_req ]# Extensions to add to a certificate requestbasicConstraints = CA:FALSEkeyUsage = nonRepudiation, digitalSignature, keyEnciphermentsubjectAltName = @alt_names[alt_names]#注意这个IP.1的设置,IP地址需要和你的服务器的监听地址一样 DNS为server网址,可设置多个ip和dnsIP.1 = 0.0.0.0DNS.1 = helloworld.com

生成server端证书

openssl x509 -days 365 -req -in server.csr -extensions  v3_req -CAkey ica.key -CA ica.crt -CAcreateserial -out server.crt  -extfile openssl.cnf

  • 创建 https 服务(nodejs ,有javaScript基础的可以去 runoob.com 自学, 没有基础的先学 javaScript)

用户家目录下新建 server 目录 ,并将刚刚生成的 server.key & server.crt 拷贝到 该目录下 
~ ] $ mkdir server && cd  server && cp ../myCA/server.key ../myCA/server.crt ~/server
server 目录下创建 server.js

// server.js server 端启动入口
// 使用nodejs自带的http、https、express、 fs、path 、url模块
const https = require('https');
const http = require('http');
const fs = require('fs');
const path = require('path');
const url = require('url');//根据项目的路径导入生成的证书文件
const privateKey  = fs.readFileSync(path.join(__dirname, './server.key'), 'utf8');
const certificate = fs.readFileSync(path.join(__dirname, './server.crt'), 'utf8');
const credentials = {key: privateKey, cert: certificate};//创建http与HTTPS服务器
const httpServer = http.createServer(function(req, res){
var pathname = url.parse(req.url).pathname;console.log("Request for http " + pathname + " received.");// ... 处理请求res.write('http request received');res.end();
});
const httpsServer = https.createServer(credentials, function(req, res){
var pathname = url.parse(req.url).pathname;console.log("Request for https" + pathname + " received.");// 请求处理res.write('https request received');res.end();
});//可以分别设置http、https的访问端口号
const PORT = 8087;
const SSLPORT = 8088;//创建http服务器
httpServer.listen(PORT, function() {
console.log('HTTP Server is running on: http://localhost:%s', PORT);
});//创建https服务器
httpsServer.listen(SSLPORT, function() {
console.log('HTTPS Server is running on: https://localhost:%s', SSLPORT);
});
至此 服务端 就搭建好了 ,可以使用浏览器地址栏直接输 https://helloworld.com:8088 访问试试,(需要在本地配host  127.0.0.1 helloworld.com)
配置完 host 之后需要打开CMD 窗口 执行 ipconfig /flushdns 刷新DNS 

Android 客户端操作

  • 创建项目并引入相关依赖

搭建 Android 项目,页面加一个 Btn 和一个 TextView即可, 为Btn 绑定点击事件对应的方法

将 khandroid-httpclient-4.2.3.jar (提取码:g72x) 添加到 项目 libs 目录下,并添加到项目依赖

并添加 httpcomponents 和 volley 框架的依赖, 操作完之后 模块的 build.gradle  中的 dependencies 节点下会多出如下三行

新起一个包路径, com.httptest.httpstoolbox 拷贝如下几个类到 该路径下

SslHttpClient

/**
* Copyright 2013 Ognyan Bankov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/package com.httpstest.httpstoolbox;import khandroid.ext.apache.http.client.params.ClientPNames;
import khandroid.ext.apache.http.conn.ClientConnectionManager;
import khandroid.ext.apache.http.conn.scheme.PlainSocketFactory;
import khandroid.ext.apache.http.conn.scheme.Scheme;
import khandroid.ext.apache.http.conn.scheme.SchemeRegistry;
import khandroid.ext.apache.http.impl.client.DefaultHttpClient;
import khandroid.ext.apache.http.impl.conn.PoolingClientConnectionManager;
import khandroid.ext.apache.http.params.HttpParams;import java.io.InputStream;
import java.security.GeneralSecurityException;public class SslHttpClient extends DefaultHttpClient {private static final int HTTP_DEFAULT_PORT = 80;private static final String HTTP_SCHEME = "http";private static final int HTTP_DEFAULT_HTTPS_PORT = 443;private static final String HTTP_SSL_SCHEME = "https";private InputStream mKeyStore;private String mKeyStorePassword;private int mHttpsPort;public SslHttpClient(InputStream keyStore, String keyStorePassword) {mKeyStore = keyStore;mKeyStorePassword = keyStorePassword;mHttpsPort = HTTP_DEFAULT_HTTPS_PORT;}public SslHttpClient(InputStream keyStore, String keyStorePassword, int httpPort) {mKeyStore = keyStore;mKeyStorePassword = keyStorePassword;mHttpsPort = httpPort;}public SslHttpClient(ClientConnectionManager conman,InputStream keyStore,String keyStorePassword) {super(conman);mKeyStore = keyStore;mKeyStorePassword = keyStorePassword;}public SslHttpClient(final ClientConnectionManager conman,final HttpParams params,InputStream keyStore,String keyStorePassword) {super(conman, checkForInvalidParams(params));this.mKeyStore = keyStore;this.mKeyStorePassword = keyStorePassword;}public SslHttpClient(final HttpParams params, InputStream keyStore, String keyStorePassword) {super(null, checkForInvalidParams(params));this.mKeyStore = keyStore;this.mKeyStorePassword = keyStorePassword;}@SuppressWarnings("deprecation")// we check intentionally for an old parameterprivate static HttpParams checkForInvalidParams(HttpParams params) {String className = (String) params.getParameter(ClientPNames.CONNECTION_MANAGER_FACTORY_CLASS_NAME);if (className != null) {throw new IllegalArgumentException("Don't try to pass ClientPNames.CONNECTION_MANAGER_FACTORY_CLASS_NAME parameter. We use our own connection manager factory anyway...");}return params;}@Overrideprotected ClientConnectionManager createClientConnectionManager() {SchemeRegistry registry = new SchemeRegistry();PlainSocketFactory pfs = PlainSocketFactory.getSocketFactory();Scheme s = new Scheme(HTTP_SCHEME, HTTP_DEFAULT_PORT, pfs);registry.register(s);PoolingClientConnectionManager ret;try {registry.register(new Scheme(HTTP_SSL_SCHEME, mHttpsPort, new SslSocketFactory(mKeyStore, mKeyStorePassword)));ret = new PoolingClientConnectionManager(registry);} catch (GeneralSecurityException e) {throw new IllegalStateException(e);}return ret;}public void setHttpsPort(int httpsPort) {mHttpsPort = httpsPort;}
}

SslSocketFactory

/**
* Copyright 2013 Ognyan Bankov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/package com.httpstest.httpstoolbox;import khandroid.ext.apache.http.conn.ssl.SSLSocketFactory;import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;class SslSocketFactory extends SSLSocketFactory {public SslSocketFactory(InputStream keyStore, String keyStorePassword) throws GeneralSecurityException {super(createSSLContext(keyStore, keyStorePassword), STRICT_HOSTNAME_VERIFIER);}private static SSLContext createSSLContext(InputStream keyStore, String keyStorePassword) throws GeneralSecurityException {SSLContext sslcontext = null;try {sslcontext = SSLContext.getInstance("TLS");sslcontext.init(null, new TrustManager[] { new SsX509TrustManager(keyStore, keyStorePassword) }, null);} catch (NoSuchAlgorithmException e) {throw new IllegalStateException("Failure initializing default SSL context", e);} catch (KeyManagementException e) {throw new IllegalStateException("Failure initializing default SSL context", e);}return sslcontext;}
}    

SsX509TrustManager

/**
* Copyright 2013 Ognyan Bankov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/package com.httpstest.httpstoolbox;import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;public class SsX509TrustManager implements X509TrustManager {private ArrayList<X509TrustManager> mX509TrustManagers = new ArrayList<X509TrustManager>();protected SsX509TrustManager(InputStream keyStore, String keyStorePassword) throws GeneralSecurityException {// first add original trust managerfinal TrustManagerFactory originalFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());originalFactory.init((KeyStore) null);for( TrustManager tm : originalFactory.getTrustManagers() ) {if (tm instanceof X509TrustManager) {mX509TrustManagers.add( (X509TrustManager)tm );}}// them add our custom trust managerX509TrustManager mX509TrustManagerCustom = fetchTrustManager(keyStore, keyStorePassword);if (mX509TrustManagerCustom != null) {mX509TrustManagers.add(mX509TrustManagerCustom);} else {throw new IllegalArgumentException("Keystore is valid but cannot find TrustManagerFactory of type X509TrustManager.");}}private X509TrustManager fetchTrustManager(InputStream keyStore, String keyStorePassword) throws GeneralSecurityException {X509TrustManager ret = null;TrustManagerFactory tmf = prepareTrustManagerFactory(keyStore, keyStorePassword);TrustManager tms[] = tmf.getTrustManagers();for (int i = 0; i < tms.length; i++) {if (tms[i] instanceof X509TrustManager) {ret = (X509TrustManager) tms[i];
//              break;}}return ret;}private TrustManagerFactory prepareTrustManagerFactory(InputStream keyStore, String keyStorePassword) throws GeneralSecurityException {TrustManagerFactory ret = null;KeyStore ks;ks = KeyStore.getInstance("BKS");try {ks.load(keyStore, keyStorePassword.toCharArray());} catch (IOException e) {throw new GeneralSecurityException("Problem reading keystore stream", e);}ret = TrustManagerFactory.getInstance("X509");ret.init(ks);return ret;}@Overridepublic void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {// Oh, I am easy!}@Overridepublic void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {boolean ok = false;for( X509TrustManager tm : mX509TrustManagers ) {try {tm.checkServerTrusted(chain,authType);ok = true;break;} catch( CertificateException e ) {// ignore}}if (!ok) {throw new CertificateException();}}@Overridepublic X509Certificate[] getAcceptedIssuers() {final ArrayList<X509Certificate> list = new ArrayList<X509Certificate>();for( X509TrustManager tm : mX509TrustManagers )list.addAll(Arrays.asList(tm.getAcceptedIssuers()));return list.toArray(new X509Certificate[list.size()]);}}

ExtHttpClientStack

/**
* Copyright 2013 Ognyan Bankov
* Portions copyright 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/package com.httpstest.httpstoolbox;import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.Request.Method;
import com.android.volley.toolbox.HttpStack;
import khandroid.ext.apache.http.Header;
import khandroid.ext.apache.http.HttpEntity;
import khandroid.ext.apache.http.HttpResponse;
import khandroid.ext.apache.http.NameValuePair;
import khandroid.ext.apache.http.client.HttpClient;
import khandroid.ext.apache.http.client.methods.*;
import khandroid.ext.apache.http.entity.ByteArrayEntity;
import khandroid.ext.apache.http.message.BasicNameValuePair;
import khandroid.ext.apache.http.params.HttpConnectionParams;
import khandroid.ext.apache.http.params.HttpParams;
import org.apache.http.ProtocolVersion;
import org.apache.http.StatusLine;
import org.apache.http.entity.BasicHttpEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.message.BasicStatusLine;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;public class ExtHttpClientStack implements HttpStack {protected final HttpClient mClient;private final static String HEADER_CONTENT_TYPE = "Content-Type";public ExtHttpClientStack(HttpClient client) {mClient = client;}private static void addHeaders(HttpUriRequest httpRequest, Map<String, String> headers) {for (String key : headers.keySet()) {httpRequest.setHeader(key, headers.get(key));}}@SuppressWarnings("unused")private static List<NameValuePair> getPostParameterPairs(Map<String, String> postParams) {List<NameValuePair> result = new ArrayList<NameValuePair>(postParams.size());for (String key : postParams.keySet()) {result.add(new BasicNameValuePair(key, postParams.get(key)));}return result;}@Overridepublic org.apache.http.HttpResponse performRequest(Request<?> request,Map<String, String> additionalHeaders)throws IOException, AuthFailureError {HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);addHeaders(httpRequest, additionalHeaders);addHeaders(httpRequest, request.getHeaders());onPrepareRequest(httpRequest);HttpParams httpParams = httpRequest.getParams();int timeoutMs = request.getTimeoutMs();// TODO: Reevaluate this connection timeout based on more wide-scale// data collection and possibly different for wifi vs. 3G.HttpConnectionParams.setConnectionTimeout(httpParams, 5000);HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);HttpResponse resp = mClient.execute(httpRequest);return convertResponseNewToOld(resp);}private org.apache.http.HttpResponse convertResponseNewToOld(HttpResponse resp)throws IllegalStateException, IOException {ProtocolVersion protocolVersion = new ProtocolVersion(resp.getProtocolVersion().getProtocol(),resp.getProtocolVersion().getMajor(),resp.getProtocolVersion().getMinor());StatusLine responseStatus = new BasicStatusLine(protocolVersion,resp.getStatusLine().getStatusCode(),resp.getStatusLine().getReasonPhrase());BasicHttpResponse response = new BasicHttpResponse(responseStatus);org.apache.http.HttpEntity ent = convertEntityNewToOld(resp.getEntity());response.setEntity(ent);for (Header h : resp.getAllHeaders()) {org.apache.http.Header header = convertheaderNewToOld(h);response.addHeader(header);}return response;}private org.apache.http.HttpEntity convertEntityNewToOld(HttpEntity ent)throws IllegalStateException, IOException {BasicHttpEntity ret = new BasicHttpEntity();if (ent != null) {ret.setContent(ent.getContent());ret.setContentLength(ent.getContentLength());Header h;h = ent.getContentEncoding();if (h != null) {ret.setContentEncoding(convertheaderNewToOld(h));}h = ent.getContentType();if (h != null) {ret.setContentType(convertheaderNewToOld(h));}}return ret;}private org.apache.http.Header convertheaderNewToOld(Header header) {org.apache.http.Header ret = new BasicHeader(header.getName(), header.getValue());return ret;}/*** Creates the appropriate subclass of HttpUriRequest for passed in request.*/@SuppressWarnings("deprecation")/* protected */static HttpUriRequest createHttpRequest(Request<?> request,Map<String, String> additionalHeaders)throws AuthFailureError {switch (request.getMethod()) {case Method.DEPRECATED_GET_OR_POST: {// This is the deprecated way that needs to be handled for backwards compatibility.// If the request's post body is null, then the assumption is that the request is// GET.  Otherwise, it is assumed that the request is a POST.byte[] postBody = request.getPostBody();if (postBody != null) {HttpPost postRequest = new HttpPost(request.getUrl());postRequest.addHeader(HEADER_CONTENT_TYPE, request.getPostBodyContentType());HttpEntity entity;entity = new ByteArrayEntity(postBody);postRequest.setEntity(entity);return postRequest;} else {return new HttpGet(request.getUrl());}}case Method.GET:return new HttpGet(request.getUrl());case Method.DELETE:return new HttpDelete(request.getUrl());case Method.POST: {HttpPost postRequest = new HttpPost(request.getUrl());postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());setEntityIfNonEmptyBody(postRequest, request);return postRequest;}case Method.PUT: {HttpPut putRequest = new HttpPut(request.getUrl());putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());setEntityIfNonEmptyBody(putRequest, request);return putRequest;}default:throw new IllegalStateException("Unknown request method.");}}private static void setEntityIfNonEmptyBody(HttpEntityEnclosingRequestBase httpRequest,Request<?> request) throws AuthFailureError {byte[] body = request.getBody();if (body != null) {HttpEntity entity = new ByteArrayEntity(body);httpRequest.setEntity(entity);}}/*** Called before the request is executed using the underlying HttpClient.** <p>* Overwrite in subclasses to augment the request.* </p>*/protected void onPrepareRequest(HttpUriRequest request) throws IOException {// Nothing.}
}
  • 生成 Android端 keystore

拷贝 bcprov-jdk16-146.jar (提取码 :e6so)  或者去官网下载相应版本 The Legion of the Bouncy Castle & 服务端根证书 server.crt 到 同一个目录下 (目录随意)

执行下面脚本 生成   my.bks文件,执行的时候 要求输入秘钥 ,这里还是输入生成 server.crt 时 输入的 pass phrase  ,最后确认信任此证书 输入 “是”

keytool -importcert -v -trustcacerts -file "server.crt" -alias imeto_alias -keystore "my.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "bcprov-jdk16-146.jar" -storetype BKS

在 Android 项目里 创建 raw 资源目录, 并将刚生成的 my.bks 添加到 raw 目录下

  • MainActivity.java & 布局文件 activity_main.xml

MainActivity.java

package com.httpstest;import android.view.View;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.httpstest.httpstoolbox.ExtHttpClientStack;
import com.httpstest.httpstoolbox.SslHttpClient;import java.io.InputStream;public class MainActivity extends AppCompatActivity {TextView tv_https_response;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv_https_response = findViewById(R.id.tv_https_response);}public void httpsGet(View v){String path = "https://helloworld.com:8088";// Replace R.raw.test with your keystoreInputStream keyStore = getResources().openRawResource(R.raw.my);// keyStore 为生成的 my.bks 文件(该文件包含 密钥实体 & 可信任的证书实体)// "jiangBUG" 为 keystorePassword // 8088 为https服务端的端口RequestQueue queue = Volley.newRequestQueue(MainActivity.this,new ExtHttpClientStack(new SslHttpClient(keyStore, "jiangBUG", 8088)));StringRequest myReq = new StringRequest(Request.Method.GET, path,createMyReqSuccessListener(),createMyReqErrorListener());queue.add(myReq);}private Response.Listener<String> createMyReqSuccessListener() {return new Response.Listener<String>() {@Overridepublic void onResponse(String response) {tv_https_response.setText(response);}};}private Response.ErrorListener createMyReqErrorListener() {return new Response.ErrorListener() {@Overridepublic void onErrorResponse(VolleyError error) {tv_https_response.setText(error.getMessage());}};}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><LinearLayoutandroid:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="15"android:textAlignment="center"android:text="This is https get response"android:id="@+id/tv_https_response"android:gravity="center" /><Buttonandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:id="@+id/btn_testhttpsGet"android:onClick="httpsGet"app:layout_constraintHorizontal_bias="0.0"android:text="test httpsGet"/></LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

AndroidManifest.xml 中添加联网权限

<!-- 联网权限 -->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
  • 修改 Android 模拟器的 hosts 文件

以可写入模式启动 AVD(Android Vitual Device),进入Android SDK 安装目录,找到 emulator.exe (高版本的 Android SDK 在Android SDK 安装目录\emulator 目录下), 低版本的 应该就在Android SDK 安装目录下

CMD 进入到该目录下 ,执行 emulator.exe -list-avds 列出所有 AVD 设备
注意: 不要用 Google Play 镜像创建的 AVD 
以可写入的模式启动 AVD  ,这里以启动 5.1_WVGA_API_26 为例, 
执行 emulator.exe -avd 5.1_WVGA_API_26 -writable-system

启动后打开 AVD的 资源管理器,找到 /system/etc/hosts文件 添加 host

注意这里的 Ip地址需要配置成你 主机的 局域网地址 而不是 127.0.0.1

使用 adb 命令

adb root root运行
adb remount 可更改用户账户
adb pull /system/etc/hosts e:/hosts 将hosts文件放到e盘的hosts下
adb push e:/hosts /system/etc/hosts 将修改完成的hosts文件放到模拟器中。

到AndroidStudio 中查看 hosts 文件内容是否已经变更

  • Android 端发送HTTPS 请求进行验证

在 AndroidStudio 中启动APP 并验证

有任何问题 请邮件联系 jiangbug@outlook.com

Android——自建CA证书,实现https请求相关推荐

  1. 信息安全实践Lab1-自建CA证书搭建https服务器

    title: 信息安全实践Lab1-自建CA证书搭建https服务器 date: 2021-12-21 02:44:40 tags: 信息安全 categories: 信息安全实践 信息安全实践Lab ...

  2. 自建CA证书搭建https服务器

    由于CA收费,所以可以自建CA,通过将CA导入浏览器实现https的效果,曾经12306购票就需要自行导入网站证书. 关于https 2015年阿里巴巴将旗下淘宝.天猫(包括移动客户端)全站启用HTT ...

  3. 信安实践——自建CA证书搭建https服务器

    https://www.cnblogs.com/libaoquan/p/7965873.html 1.理论知识 https简介 HTTPS(全称:Hyper Text Transfer Protoco ...

  4. 腾讯云CentOS自建CA证书搭建https服务器

    为了完成实验以及不同电脑虚拟机不同,索性买了一个腾讯云的服务器,学生价,很便宜. 实验环境:CentOS7.5,Apache 2.4.6 OpenSSL 1.0.2k 理论知识 Http和Https的 ...

  5. 利用openssl自建ca并且使apache2用自建的ca证书进行https链接(自用,,,

    参考了信安实践--自建CA证书搭建https服务器 - LiBaoquan - 博客园 (cnblogs.com) 加一些关于apache的命令: sudo systemctl start apach ...

  6. 自建CA证书以及导入到浏览器实现https安全连接

    自建CA证书以及导入到浏览器实现https安全连接 安装 openssl(一般centos 系统都会自带安装好的了) 目录:/etc/pki/CA/ yum install openssl opens ...

  7. iOS 用自签名证书实现 HTTPS 请求的原理实例讲解

    在16年的WWDC中,Apple已表示将从2017年1月1日起,所有新提交的App必须强制性应用HTTPS协议来进行网络请求.默认情况下非HTTPS的网络访问是禁止的并且不能再通过简单粗暴的向Info ...

  8. iOS 用自签名证书实现 HTTPS 请求的原理

    在16年的WWDC中,Apple已表示将从2017年1月1日起,所有新提交的App必须强制性应用HTTPS协议来进行网络请求.默认情况下非HTTPS的网络访问是禁止的并且不能再通过简单粗暴的向Info ...

  9. [Linux] centos 6.5 httpd 自建CA 认证 实现 https 服务

    httpd 自建CA 认证 实现 https 服务 需要的软件: httpd mod_ssl openssl 本文将CA证书服务器和 httpd服务器放到一台物理机器上实现的, 可以作为学习的参考. ...

最新文章

  1. java_io_listFile()的应用和匿名内部类
  2. Android 系统(272)---Android中的各种保活
  3. Altium AD20更改原理图背景颜色
  4. win7卸载显卡及对应驱动后桌面分辨率不对以及鼠标键盘无反应
  5. java 二进制转十进制的算法_java中位运算与整数的十进制转二进制
  6. 帆软报表嵌入python程序_C#教程之C#服务器端生成报告文档:使用帆软报表
  7. 计算机机房实训计划,计算机专业实习计划安排.docx
  8. 天泉证道四句教与价值观
  9. Titan XP值不值?教你如何挑选深度学习GPU
  10. android room数据库embed,Android官方ORM数据库Room技术解决方案 @Embedded内嵌对象
  11. 到底要不要孩子学习机器人编程
  12. 信息安全服务资质认证实施规则
  13. 掌上智维技术支持 App Tech Support
  14. Linux服务器搭建----Web服务器(apache)
  15. UIP和lwip的区别
  16. TI杯基于FDC2214的手势识别设计(黑龙江省赛)
  17. 目标检测数据集:坦克(1)
  18. 手臂疼,竟是它惹的祸?这些征兆你想都想不到
  19. 80篇各ajax框架入门教程
  20. 数论概论读书笔记 13.素数的计数

热门文章

  1. 医学图像处理——影像组学的建模过程
  2. win10wifi开关自动弹回_win10wlan开关自动弹回
  3. JeeSite(2):导入数据,进入系统
  4. 易基因技术推介|简化基因组甲基化测序研究解决方案
  5. GitLab 服务搭建
  6. -bash:........ Permission denied
  7. 使用Flutter实现仿微信录音的插件
  8. [译]Unity3D Shader教程(五)Surface Shader Basics
  9. C盘清理及可清理文件详解(Windows 7)-简单易操作_让你的C盘彻底解放
  10. 怎么录屏?5 款免费无水印的录屏神器