####补间动画的分类和Interpolator
Andoird所支持的补间动画效果有如下这五种,或者说四种吧,第五种是前面几种的组合而已~

  • AlphaAnimation:透明度渐变效果,创建时许指定开始以及结束透明度,还有动画的持续 时间,透明度的变化范围(0,1),0是完全透明,1是完全不透明;对应标签!
  • ScaleAnimation:缩放渐变效果,创建时需指定开始以及结束的缩放比,以及缩放参考点, 还有动画的持续时间;对应标签!
  • TranslateAnimation:位移渐变效果,创建时指定起始以及结束位置,并指定动画的持续 时间即可;对应标签!
  • RotateAnimation:旋转渐变效果,创建时指定动画起始以及结束的旋转角度,以及动画 持续时间和旋转的轴心;对应标签
  • AnimationSet:组合渐变,就是前面多种渐变的组合,对应标签

#####先要来了解一个东西:Interpolator
用来控制动画的变化速度,可以理解成动画渲染器,当然我们也可以自己实现Interpolator 接口,自行来控制动画的变化速度,而Android中已经为我们提供了五个可供选择的实现类:

  • LinearInterpolator:动画以均匀的速度改变
  • AccelerateInterpolator:在动画开始的地方改变速度较慢,然后开始加速
  • AccelerateDecelerateInterpolator:在动画开始、结束的地方改变速度较慢,中间时加速
  • CycleInterpolator:动画循环播放特定次数,变化速度按正弦曲线改变: Math.sin(2 * mCycles * Math.PI * input)
  • DecelerateInterpolator:在动画开始的地方改变速度较快,然后开始减速
  • AnticipateInterpolator:反向,先向相反方向改变一段再加速播放
  • AnticipateOvershootInterpolator:开始的时候向后然后向前甩一定值后返回最后的值
  • BounceInterpolator: 跳跃,快到目的值时值会跳跃,如目的值100,后面的值可能依次为85,77,70,80,90,100
  • OvershottInterpolator:回弹,最后超出目的值然后缓慢改变到目的值
    而这个东东,我们一般是在写动画xml文件时会用到,属性是:android:interpolator, 而上面对应的值是:@android:anim/linear_interpolator,其实就是驼峰命名法变下划线而已 AccelerateDecelerateInterpolator对应:@android:anim/accelerate_decelerate_interpolator!

####各种动画的详细讲解
动画的xml文件都是建在res下的anim文件夹内
这里的android:duration都是动画的持续时间,单位是毫秒~
####AlphaAnimation(透明度渐变)

1
2
3
4
5
<alpha xmlns:android="http://schemas.android.com/apk/res/android"  
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromAlpha="1.0"
android:toAlpha="0.1"
android:duration="2000"/>

属性解释:

  • fromAlpha :起始透明度
  • toAlpha:结束透明度
  • 透明度的范围为:0-1,完全透明-完全不透明

####ScaleAnimation(缩放渐变)

1
2
3
4
5
6
7
8
9
<scale xmlns:android="http://schemas.android.com/apk/res/android"  
android:interpolator="@android:anim/accelerate_interpolator"
android:fromXScale="0.2"
android:toXScale="1.5"
android:fromYScale="0.2"
android:toYScale="1.5"
android:pivotX="50%"
android:pivotY="50%"
android:duration="2000"/>

属性解释:

  • fromXScale/fromYScale:沿着X轴/Y轴缩放的起始比例
  • toXScale/toYScale:沿着X轴/Y轴缩放的结束比例
  • pivotX/pivotY:缩放的中轴点X/Y坐标,即距离自身左边缘的位置,比如50%就是以图像的 中心为中轴点

####TranslateAnimation(位移渐变)

1
2
3
4
5
6
7
<translate xmlns:android="http://schemas.android.com/apk/res/android"  
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromXDelta="0"
android:toXDelta="320"
android:fromYDelta="0"
android:toYDelta="0"
android:duration="2000"/>

属性解释:

  • fromXDelta/fromYDelta:动画起始位置的X/Y坐标
  • toXDelta/toYDelta:动画结束位置的X/Y坐标

####RotateAnimation(旋转渐变)

1
2
3
4
5
6
7
8
9
<rotate xmlns:android="http://schemas.android.com/apk/res/android"  
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromDegrees="0"
android:toDegrees="360"
android:duration="1000"
android:repeatCount="1"
android:pivotX="50.0%"
android:pivotY="50.0%"
android:repeatMode="reverse"/>

属性解释:

  • fromDegrees/toDegrees:旋转的起始/结束角度
  • repeatCount:旋转的次数,默认值为0,代表一次,假如是其他值,比如3,则旋转4次 另外,值为-1或者infinite时,表示动画永不停止
  • repeatMode:设置重复模式,默认restart,但只有当repeatCount大于0或者infinite或-1时 才有效。还可以设置成reverse,表示偶数次显示动画时会做方向相反的运动!

####AnimationSet(组合渐变)
非常简单,就是前面几个动画组合到一起而已~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<set xmlns:android="http://schemas.android.com/apk/res/android"  
android:interpolator="@android:anim/decelerate_interpolator"
android:shareInterpolator="true" >

<scale
android:duration="2000"
android:fromXScale="0.2"
android:fromYScale="0.2"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1.5"
android:toYScale="1.5" />

<rotate
android:duration="1000"
android:fromDegrees="0"
android:repeatCount="1"
android:repeatMode="reverse"
android:toDegrees="360" />

<translate
android:duration="2000"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="320"
android:toYDelta="0" />

<alpha
android:duration="2000"
android:fromAlpha="1.0"
android:toAlpha="0.1" />
</set>

####动画调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_alpha:
Animation animation = AnimationUtils.loadAnimation(this,
R.anim.anim_alpha);
img_show.startAnimation(animation);
break;
case R.id.btn_scale:
Animation animation = AnimationUtils.loadAnimation(this,
R.anim.anim_scale);
img_show.startAnimation(animation);
break;
case R.id.btn_tran:
Animation animation = AnimationUtils.loadAnimation(this,
R.anim.anim_translate);
img_show.startAnimation(animation);
break;
case R.id.btn_rotate:
Animation animation = AnimationUtils.loadAnimation(this,
R.anim.anim_rotate);
img_show.startAnimation(animation);
break;
case R.id.btn_set:
Animation animation = AnimationUtils.loadAnimation(this,
R.anim.anim_set);
img_show.startAnimation(animation);
break;
}
}

####动画状态的监听
我们可以对动画的执行状态进行监听,调用动画对象的:
setAnimationListener(new AnimationListener())方法,重写下面的三个方法:

  • onAnimationStart():动画开始
  • onAnimtaionRepeat():动画重复
  • onAnimationEnd():动画结束
    即可完成动画执行状态的监听~

####为View动态设置动画效果
先调用AnimationUtils.loadAnimation(动画xml文件),然后View控件调用startAnimation(anim) 开始动画这是静态加载的方式,当然你也可以直接创建一个动画对象,用Java代码完成设置,再调用 startAnimation开启动画
####注意
补间动画位置改变后,其位置还是在原来的地方只是视图位置改变了,像按钮的点击事件还是在原来的地方!

第一步 新建AppGlideModule:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.guoshikeji.dramecard.utils;

import android.content.Context;
import android.support.annotation.NonNull;
import android.util.Log;

import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.Registry;
import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.module.AppGlideModule;
import java.io.InputStream;

/**
* Register {@link FlickrModelLoader} for the Flickr sample app.
*/

@GlideModule
public class FlickrGlideModule extends AppGlideModule {

@Override
public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
super.applyOptions(context, builder);
// builder.setDefaultRequestOptions(new RequestOptions().format(DecodeFormat.PREFER_ARGB_8888));
}

@Override
public void registerComponents(@NonNull Context context, @NonNull Glide glide,
@NonNull Registry registry) {
Log.e("tyl","-----registerComponents-------");
registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());
}
@Override
public boolean isManifestParsingEnabled() {
return false;
}

}

第二步 AndroidManifest.xml中配置meta-data :

1
2
3
4
5
6
  <application>
<meta-data
android:name="com.guoshikeji.dramecard.utils.FlickrGlideModule"
android:value="GlideModule" />
<!--activitys />-->
<application/>

第三步 proguard-rules.pro文件中忽略GlideModule混淆:

1
2
3
#GlideModule路径
-keepnames class com.guoshikeji.dramecard.utils.FlickrGlideModule
-keepresourcexmlelements manifest/application/meta-data@value=GlideModule

第四步 在继承AppGlideModule类的registerComponents方法中添加忽略证书认证:

1
2
registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());
<!--重点是这句话:new OkHttpUrlLoader.Factory()-->

重写OkHttpUrlLoader类的Factory,给OkHttpClient添加证书认证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> {
private static volatile Call.Factory internalClient;
private final Call.Factory client;
private static Call.Factory getInternalClient() {
// glide添加双向认证
OkHttpClient.Builder okHttpClient = new OkHttpClient().newBuilder();
okHttpClient.hostnameVerifier(new Home());//忽略证书域名不受信任问题
okHttpClient.sslSocketFactory(MySSLSocketFactory.getSocketFactory(MyApplication.getInstance()));//添加证书
OkHttpClient build = okHttpClient.build();
if (internalClient == null) {
synchronized (Factory.class) {
if (internalClient == null) {
internalClient = build;
}
}
}
return internalClient;
}
private static class Home implements HostnameVerifier {
public SSLSession sslSession;

@Override
public boolean verify(String hostname, SSLSession session) {
this.sslSession = session;
return true;
}
}

添加证书的MySSLSocketFactory类代码可复制https://www.jianshu.com/p/6229d10d3550中的SSLSocketFactory类和X509TrustManager 这2个类即可!

####各类知识点整理:

####工具类:

####源码:

1.请先下载第三方转换工具protecle,配置java环境
下载链接: http://download.csdn.net/detail/zhangyong125/9376667
image.png
2.点击运行protecle.jar
3.新建BKSStore
image.png
image.png
4.导入p12密钥对(p12文件),包含公钥和私钥
image.png
image.png
4.修改别名
image.png
image.png
5.为客户端的私钥创建密码
image.png
image.png
6.另存为BKS
image.png
image.png

####各类知识点整理:

####工具类:

####源码:

####各类知识点整理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 单双向验证基础知识点:https://www.jianshu.com/p/ea5f4b1d9c00
phpstudy搭建本地服务器:https://www.jianshu.com/p/bbf853fc28f3
浏览器获取证书文件(p12转cer):https://www.jianshu.com/p/7f74acab6c74
https双向认证证书生成:https://www.jianshu.com/p/094c7fc8cb85
android okhttps双向验证(代码实现):https://www.jianshu.com/p/6229d10d3550
android webView的双向验证:https://www.jianshu.com/p/e98119d04fd9
配置完成后的测试:https://www.jianshu.com/p/cfcf708a591a
Glide okhttps证书验证全局配置:https://www.jianshu.com/p/ac0b5c5f3ca7

工具类:

P12证书转BKS证书:https://www.jianshu.com/p/2a96c36b27fe
服务器网址检测(兼容性及协议检测):https://www.ssllabs.com/index.html

源码:

github:https://github.com/fs437563/android_https

使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
  public void getHttps() {
try {
OkHttpClient mOkHttpClient = null;
mOkHttpClient = new OkHttpClient().newBuilder()
// 主要就是下面2句,其他的和正常请求都一样的
.hostnameVerifier(new Home())//忽略服务器域名不信任警告
.sslSocketFactory(MySSLSocketFactory.getSocketFactory(MainActivity.this))//加入证书
.build();
Request request = new Request.Builder()
.url(url)
.build();
Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, final IOException e) {
Log.e("tyl", "onFailure=" + e.getMessage());
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
Log.e("tyl", "onResponse=" + response.body().string());
}
});
} catch (Exception e) {
Log.e("tyl", "IOException=" + e);
e.printStackTrace();
}
}

public class Home implements HostnameVerifier {
public SSLSession sslSession;

@Override
public boolean verify(String hostname, SSLSession session) {
this.sslSession = session;
return true;
}
}

证书文件放在:
证书文件位置

SSLSocketFactory:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package com.tgdz.my.testhttps;

import android.content.Context;
import android.util.Log;

import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

/**
* Created by tyl
* 2018/7/9/009
* Describe:
*/

public class MySSLSocketFactory {
private static final String KEY_STORE_TYPE_BKS = "bks";//证书类型
private static final String KEY_STORE_TYPE_P12 = "PKCS12";//证书类型
private static final String KEY_STORE_PASSWORD = "123456";//证书密码(应该是客户端证书密码,没有密码的直接改为空字符串)
private static final String KEY_STORE_TRUST_PASSWORD = "123456";//授信证书密码(应该是服务端证书密码)
private static InputStream trust_input;
private static InputStream client_input;

public static SSLSocketFactory getSocketFactory(Context context) {
// 可以使用bks和client.cer来验证 去掉注释的代码,client.p12替换ca.p12即可,也可以直接通过p12我测试的时候也是通过的
try {
//服务器授信证书
// trust_input = context.getResources().getAssets().open("client.bks");
//客户端证书
client_input = context.getResources().getAssets().open("ca.p12");
SSLContext sslContext = SSLContext.getInstance("TLS");
// KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
// trustStore.load(trust_input, KEY_STORE_TRUST_PASSWORD.toCharArray());
// KeyStore存放证书及密匙的仓库
KeyStore keyStore = KeyStore.getInstance(KEY_STORE_TYPE_P12);
keyStore.load(client_input, KEY_STORE_PASSWORD.toCharArray());
// KeyManagerFactory证书管理类
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, KEY_STORE_PASSWORD.toCharArray());
// 核心代码 SSLContext此类的实例表示安全套接字协议的实现, 它是SSLSocketFactory、SSLServerSocketFactory和SSLEngine的工厂。
// 这里注意有一个坑,之前我写的时候参考的网上文档大部分都是使用的是TrustManager系统默认的证书管理器但是自建证书需要使用X509TrustManager来实现
sslContext.init(keyManagerFactory.getKeyManagers(),new TrustManager[]{new TrustAllCerts()}, new SecureRandom());

SSLSocketFactory factory = sslContext.getSocketFactory();

return factory;

} catch (Exception e) {
e.printStackTrace();
Log.e("tyl","Exception="+e.getMessage());
return null;
} finally {
try {
// trust_input.close();
client_input.close();
} catch (IOException e) {
e.printStackTrace();
Log.e("tyl","Exception="+e.getMessage());
}
}
}
};

X509TrustManager :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.tgdz.my.testhttps;

import android.util.Log;

import java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;

/**
* Created by tyl
* 2018/7/12/012
* Describe:
*/


public class TrustAllCerts implements X509TrustManager {
// 默认的下面3个接口都会抛出一个异常,这里直接去掉异常,就是客户端忽略验证服务器端的验证信息直接通过
@Override
public void checkClientTrusted(
X509Certificate[] chain, String authType) {
Log.e("tyl","checkClientTrusted");
}

@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
Log.e("tyl","checkServerTrusted");
}

@Override
public X509Certificate[] getAcceptedIssuers() {
Log.e("tyl","getAcceptedIssuers");
return new X509Certificate[]{};}
}

####各类知识点整理:

####工具类:

####源码:

使用:

1
my_webview.setWebViewClient(new SslWebViewClient(this));

直接复制下面2个类之后webview调用(虽然代码有点多,但其实有很多是没有用到的!只是因为不同证书类型可能会用到不同的代码而暂时保留)

com.tgdz.my.testhttps;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

import android.util.Log;

import java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;

/**
* Created by tyl
* 2018/7/12/012
* Describe:
*/


public class TrustAllCerts implements X509TrustManager {
// 默认的下面3个接口都会抛出一个异常,这里直接去掉异常,就是客户端忽略验证服务器端的验证信息直接通过
@Override
public void checkClientTrusted(
X509Certificate[] chain, String authType) {
Log.e("tyl","checkClientTrusted");
}

@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
Log.e("tyl","checkServerTrusted");
}

@Override
public X509Certificate[] getAcceptedIssuers() {
Log.e("tyl","getAcceptedIssuers");
return new X509Certificate[]{};}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
package com.tgdz.my.testhttps;
import android.annotation.TargetApi;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

public class SslWebViewClient extends WebViewClient {

private SSLContext sslContext;
private static final String KEY_STORE_TYPE_BKS = "bks";//证书类型
private static final String KEY_STORE_TYPE_P12 = "PKCS12";//证书类型
private static final String KEY_STORE_PASSWORD = "";//证书密码(应该是客户端证书密码)
private static final String KEY_STORE_TRUST_PASSWORD = "123456";//授信证书密码(应该是服务端证书密码)
private static InputStream trust_input;
private static InputStream client_input;

public SslWebViewClient(Context context) {
try {
//服务器授信证书
// trust_input = context.getResources().getAssets().open("client.bks");
//客户端证书
client_input = context.getResources().getAssets().open("ca.p12");
sslContext = SSLContext.getInstance("TLS");
// KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
// trustStore.load(trust_input, KEY_STORE_TRUST_PASSWORD.toCharArray());
KeyStore keyStore = KeyStore.getInstance(KEY_STORE_TYPE_P12);
keyStore.load(client_input, KEY_STORE_PASSWORD.toCharArray());
// TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
// trustManagerFactory.init(trustStore);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, KEY_STORE_PASSWORD.toCharArray());
sslContext.init(keyManagerFactory.getKeyManagers(),new TrustManager[]{new TrustAllCerts()}, new SecureRandom());
// SSLSocketFactory factory = sslContext.getSocketFactory();

} catch (Exception e) {
e.printStackTrace();
Log.e("tyl","Exception="+e.getMessage());
} finally {
try {
// trust_input.close();
client_input.close();
} catch (IOException e) {
e.printStackTrace();
Log.e("tyl","Exception="+e.getMessage());
}
}
}

@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
return processRequest(Uri.parse(url));
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
return processRequest(request.getUrl());
}

private WebResourceResponse processRequest(Uri uri) {
try {
//设置连接
URL url = new URL(uri.toString());
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
//为request设置SSL Socket Factory
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());

urlConnection.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});

//获取请求的内容、contentType、encoding
InputStream inputStream = urlConnection.getInputStream();
String contentType = urlConnection.getContentType();
String encoding = urlConnection.getContentEncoding();
if (null != contentType){
String mimeType = contentType;
if (contentType.contains(";")){
mimeType = contentType.split(";")[0].trim();
}
//返回新的response
return new WebResourceResponse(mimeType, encoding, inputStream);
}

} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}

private TrustManager[] prepareTrustManager(InputStream... certificates) {
if (certificates == null || certificates.length <= 0){
return null;
}
try {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
int index = 0;
for (InputStream certificate : certificates) {
String certificateAlias = Integer.toString(index++);
keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
try {
if (certificate != null)
certificate.close();
} catch (IOException e){

}
}
TrustManagerFactory trustManagerFactory = null;
trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
return trustManagers;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;

}

private KeyManager[] prepareKeyManager(InputStream bksFile, String password) {
try {
if (bksFile == null || password == null){
return null;
}
KeyStore clientKeyStore = KeyStore.getInstance("BKS");
clientKeyStore.load(bksFile, password.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientKeyStore, password.toCharArray());
return keyManagerFactory.getKeyManagers();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

private static X509TrustManager chooseTrustManager(TrustManager[] trustManagers) {
for (TrustManager trustManager : trustManagers) {
if (trustManager instanceof X509TrustManager) {
return (X509TrustManager) trustManager;
}
}
return null;
}

public static class MyTrustManager implements X509TrustManager{
private X509TrustManager defaultTrustManager;
private X509TrustManager localTrustManager;

public MyTrustManager(X509TrustManager localTrustManager) throws NoSuchAlgorithmException, KeyStoreException {
TrustManagerFactory var4 = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
var4.init((KeyStore) null);
defaultTrustManager = chooseTrustManager(var4.getTrustManagers());
this.localTrustManager = localTrustManager;
}

@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {

}

@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
try {
defaultTrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException ce) {
localTrustManager.checkServerTrusted(chain, authType);
}
}

@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}

public static class UnSafeTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}

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

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


}

####各类知识点整理:

####工具类:

####源码:

单向认证和双向认证的区别:

  • 单向认证只要求站点部署了ssl证书就行,任何用户都可以去访问(IP被限制除外等),只是服务端提供了身份认证。
  • 而双向认证则是需要是服务端需要客户端提供身份认证,只能是服务端允许的客户能去访问,安全性相对于要高一些
  • 双向认证SSL 协议的具体通讯过程,这种情况要求服务器和客户端双方都有证书。
  • 单向认证SSL 协议不需要客户端拥有CA证书,以及在协商对称密码方案,对称通话密钥时,服务器发送给客户端的是没有加过密的(这并不影响SSL过程的安全性)密码方案。
  • 这样,双方具体的通讯内容,就是加密过的数据。
  • 如果有第三方攻击,获得的只是加密的数据,第三方要获得有用的信息,就需要对加密的数据进行解密,这时候的安全就依赖于密码方案的安全。
  • 而幸运的是,目前所用的密码方案,只要通讯密钥长度足够的长,就足够的安全。这也是我们强调要求使用128位加密通讯的原因。
  • 一般Web应用都是采用单向认证的,原因很简单,用户数目广泛,且无需做在通讯层做用户身份验证,一般都在应用逻辑层来保证用户的合法登入。
  • 但如果是企业应用对接,情况就不一样,可能会要求对客户端(相对而言)做身份验证。这时就需要做双向认证。
    单向认证和双向认证的过程:
    单向认证

####各类知识点整理:

####工具类:

####源码:

我们作为android前端,一般获取证书的方式就2种:
1:服务器组直接给(之前在写的时候看到好多网上的文档,都说的java要jks文件,android用bks文件,但是我写好之后测试后台给我的p12文件就直接可以的);
2:从浏览器获取(也可以说是p12转cer的一种方式,下面以谷歌浏览器为例,):
1
image.png
选择证书:
选择证书
1533286342.jpg
image.png
指定导出后文件位置
记得加上.cer的后缀名
image.png
image.png
image.png

####各类知识点整理:

####工具类:

####源码:

前期准备:
ssl证书生成一般可以通过2种工具:java环境下的keytool和openssl 但是大部分使用的都是openssl网上的命令文档也是以openssl居多,下面以openssl举例;
penSSL 是一个安全套接字层密码库,囊括主要的密码算法、常用的密钥和证书封装管理功能及SSL协议,并提供丰富的应用程序供测试或其它目的使用。
单独下载openssl的话需要配置环境,这点可以自行百度进行配置!
我这边因为还需要配置phpsudy服务器而phpstudy自带有openssl工具所以我就没有去单独下载,后面也是以phpstudy自带的openssl为例说明:
phpstudy本地路劲:PHPStudy\PHPTutorial\Apache\bin\openssl
比如正常的openssl命令是下面这样:

1
openssl genrsa -des3 -out ca.key 2048

使用的时候则把openssl指向自己本地路劲的位置即可:

1
F:\PHPStudy\PHPTutorial\Apache\bin\openssl genrsa -des3 -out ca.key 2048

下面则直接使用正常命令,路劲手动替换一下即可:
win系统下新建一个文件夹用系统管理员打开windows.powershell界面:
快速打开windows.powershell
image.png
开始正式生成证书:
1.CA私钥: ca.key

1
openssl genrsa -out ca.key 1024

 CA私钥: ca.key

2.创建根证书请求文件ca.csr:

1
openssl req -new -out ca.csr -key ca.key.key

这里需要填入配置信息:

1
2
3
4
5
6
7
8
9
Country Name (2 letter code) [AU]:cn 国家名(2个字母的代号)
State or Province Name (full name) [Some-State]:cq 省
Locality Name (eg, city) []:cq 市
Organization Name (eg, company) [Internet Widgits Pty Ltd]:gs 公司名
Organizational Unit Name (eg, section) []:gs 组织或部门名
Common Name (eg, YOUR name) []:test.com 域名(尽量用服务器域名,不然会引起服务器警告)
Email Address []: 邮箱地址(不填直接回车)
A challenge password []:123456 密码
An optional company name []:gs 公司名

ca.csr

3.自签根证书ca.cer:

1
openssl x509 -req -in ca.csr -out ca.cer -signkey ca.key -CAcreateserial -days 3650

ca.cer

4.生成p12格式根证书ca.p12(密码填写123456,之前ca.csr的密码,ps:这里输入的时候是不可见的输入完成后回车即可)

1
openssl pkcs12 -export -clcerts -in ca.cer -inkey ca.key -out ca.p12

ca.p12
5.生成服务端key server.key:

1
F:\PHPStudy\PHPTutorial\Apache\bin\openssl genrsa -out server.key 1024

server.key
6.生成服务端请求文件 server.csr

1
openssl req -new -out server.csr -key server.key

填入证书配置信息:

1
2
3
4
5
6
7
8
9
Country Name (2 letter code) [AU]:cn 国家名(2个字母的代号)
State or Province Name (full name) [Some-State]:cq 省
Locality Name (eg, city) []:cq 市
Organization Name (eg, company) [Internet Widgits Pty Ltd]:gs 公司名
Organizational Unit Name (eg, section) []:gs 组织或部门名
Common Name (eg, YOUR name) []:test.com 域名(尽量用服务器域名,不然会引起服务器警告)
Email Address []: 邮箱地址
A challenge password []:123456 密码
An optional company name []:gs 公司名

server.csr
7.生成服务端证书server.cer(ca.cer,ca.key,servr.key,server.csr这4个生成服务端证书):

1
openssl x509 -req -in server.csr -out server.cer -signkey server.key -CA ca.cer -CAkey ca.key -CAcreateserial -days 3650

server.cer
8.生成客户端key client.key:

1
openssl genrsa -out client.key 1024

image.png
9.生成客户端请求文件client.csr:

1
openssl req -new -out client.csr -key client.key

填入证书配置信息:

1
2
3
4
5
6
7
8
9
Country Name (2 letter code) [AU]:cn 国家名(2个字母的代号)
State or Province Name (full name) [Some-State]:cq 省
Locality Name (eg, city) []:cq 市
Organization Name (eg, company) [Internet Widgits Pty Ltd]:gs 公司名
Organizational Unit Name (eg, section) []:gs 组织或部门名
Common Name (eg, YOUR name) []:tyl 签发机构\开发者人员(这里随意)
Email Address []: 邮箱地址
A challenge password []:123456 密码
An optional company name []:gs 公司名

client.csr
10.生成客户端证书 client.cer:

1
openssl x509 -req -in client.csr -out client.cer -signkey client.key -CA ca.cer -CAkey ca.key -CAcreateserial -days 3650

client.cer
11.生成客户端p12格式根证书client.p12(密码设置123456):

1
openssl pkcs12 -export -clcerts -in client.cer -inkey client.key -out client.p12

client.p12
至此,证书就制作完毕了:
image.png
服务器端配置(详细配置过程可见:https://www.jianshu.com/p/bbf853fc28f3):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
server {
listen 443 ssl; #http的端口号是80,https的端口为443
server_name www.test.com #服务器域名 配置多个时不要添加;号即可
ServerName 127.0.0.1
ServerName 192.168.0.111;
ssl on; #开启ssl


ssl_certificate C:\Users\Administrator\Desktop\ssl4\server.cer; #服务器证书文件
ssl_certificate_key C:\Users\Administrator\Desktop\ssl4\server.key; #服务器证书密匙
ssl_client_certificate C:\Users\Administrator\Desktop\ssl4\ca.cer; #根证书
ssl_verify_depth 1;
ssl_verify_client on; #开启客户端验证

location / {
root F:\PHPStudy\PHPTutorial\WWW; #本地网站文件目录
index index.HTML index.html index.htm ;
}
}

小建议:
制作的时候有的命令可以自行修改的,如证书名称等。
可自建一个txt文本,把openssl命令复制进去后再进行修改好后,才复制到windows powershell界面中执行
注意:
windows powershell执行openssl命令不能有错误提示,认真比对一下证书生成过后的提示,哪怕是警告也可能造成证书是失效的!我就踩过不少的坑,有的错误可以自行百度错误提示解决!

以本地服务器为例(我的本地域名配置的是www.test.com):
浏览器打开浏览器输入https://www.test.com/出现下面的界面,这是现在还没有导入证书服务器拒绝访问:
image.png
谷歌浏览器为例:

打开浏览器设置-高级-管理证书-导入-下一步-浏览(选择证书路劲,选中client.p12,文件类型那里改为全部类型就可以看到p12文件了)-输入p12证书密码-下一步一直至完成即可-导入完成后重启浏览器-输入https://www.test.com/-弹出证书导入弹窗选择确定-正常访问目标网页!
弹出证书
访问成功
备注:因为我们是android端,这里其实只是浏览器可以进行服务器访问了,但是我们在手机端进行访问的话,还是会找不到本地服务器地址,这是因为服务器还需要配置局域网访问,我这里是直接通过配置dns服务器来解决的,相关资料可自行百度!

####各类知识点整理:

####工具类:

####源码: