//超时
final HttpUrl url = chain.request().url();
throw WeakNetworkManager.get().simulateTimeOut(url.host(), url.port());
case WeakNetworkManager.TYPE_SPEED_LIMIT:
//限速
return WeakNetworkManager.get().simulateSpeedLimit(chain);
default:
//断网
throw WeakNetworkManager.get().simulateOffNetwork(chain.request().url().host());
}
}
}
实现一个OkHttp的Intercepter,根据不同的状态来进行延迟,例如如下的模拟超时
/**
- 模拟超时
- @param host
- @param port
*/
public SocketTimeoutException simulateTimeOut(String host, int port) {
SystemClock.sleep(mTimeOutMillis);
return new SocketTimeoutException(String.format(“failed to connect to %s (port %d) after %dms”, host, port, mTimeOutMillis));
}
根据Interceptor 可以干很多事情,那么Interceptor到底是什么样的原理呢?
Interceptor原理
先看一下Interceptor的原型
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
}
再看一下OkHttp源码,可以知道,我们的请求最终都会被调用到RealCall中,并执行到如下代码
@Override protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain();
}
…
}
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
在getResponseWithInterceptorChain 添加了很多OkHttp自定义的拦截器,其中有重定向,Cache,连接请求,发起请求到服务端等。我们来看一下最后几行 代码,RealInterceptorChain是一个Interceptor.Chain类型,并执行chain.proceed,接着看一下proceed方法
//RealInterceptorChain
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
…
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
…
return response;
}
重点看一下Call the next interceptor in the chain 下面几行代码,他把当前的interceptor.intercept()时,传入的是下一个interceptor的包装类,RealInterceptorChain 这样就实现了,链式递归调用了,直到最后一个response返回,才会依次返回到第一个interceptor。
可以用如下图大致描述
讲了那么多相关的知识点,我们来回到正题,上述推荐小工具的实现步骤介绍
抓包工具实现主要步骤介绍
添加一个抓包入口
在Manifest中注册即可,如下
暴露Interceptor
public final class CaptureInfoInterceptor implements Interceptor{
@Override public Response intercept(Chain chain) throws IOException {
//获取request 所有信息
…
//获取response 所有信息
…
//存储抓包数据
CacheUtils.getInstance().saveCapture(request.url().toString(),captureEntity);
}
}
这里其中有两种方式,添加到OkHttp的Interceptor,一种硬编码,如下
new OkHttpClient.Builder()
.addInterceptor(new CaptureInfoInterceptor())
.build();
另一种方式 采用字节码注入的形式,关于字节码注入,可以简单参考我的另一篇Gradle学习笔记,自定义 Transform部分。
存储和读取抓包数据 效率问题
存储时,为了不影响到主APP的网络请求效率,需要在单独的线程中执行IO操作,这里使用了单线程池
public class DiskIOThreadExecutor implements Executor {
private final Executor mDiskIO;
public DiskIOThreadExecutor() {
mDiskIO = Executors.newSingleThreadExecutor();
}
@Override
public void execute(@NonNull Runnable command) {
mDiskIO.execute(command);
}
}
存储
public void saveCapture(final String url, final CaptureEntity value) {
Runnable runnable = new Runnable() {
@Override
public void run() {
String saveUrl = url;
if (url.contains(“?”)) {
saveUrl = saveUrl.substring(0, saveUrl.indexOf(“?”));
}
String key = urlMd5(saveUrl);
sp.edit().putString(key, saveUrl).apply();
checkOrCreateFilePath(key);
File file = new File(captureFilePath + “/” + key + “/” + getCurrentTime() + “.txt”);
BufferedSink bufferedSink = null;
try {
file.createNewFile();
bufferedSink = Okio.buffer(Okio.sink(file));
bufferedSink.writeString(JSON.toJSONString(value), StandardCharsets.UTF_8);
bufferedSink.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bufferedSink != null) {
try {
bufferedSink.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
};
diskIOThreadExecutor.execute(runnable);
}
读取
读取抓包数据时,不直接读取全部的数据,只读取当前抓包的目录,数据,点击时,在去加载对应的数据
最后
分享一份工作1到5年以上的Android程序员架构进阶学习路线体系,希望能对那些还在从事Android开发却还不知道如何去提升自己的,还处于迷茫的朋友!
-
阿里P7级Android架构师技术脑图;查漏补缺,体系化深入学习提升
-
**全套体系化高级架构视频;**七大主流技术模块,视频+源码+笔记
有任何问题,欢迎广大网友一起来交流
事Android开发却还不知道如何去提升自己的,还处于迷茫的朋友!**
-
阿里P7级Android架构师技术脑图;查漏补缺,体系化深入学习提升
[外链图片转存中…(img-EpxQQao2-1719485411509)]
-
**全套体系化高级架构视频;**七大主流技术模块,视频+源码+笔记
[外链图片转存中…(img-fN4Z4vag-1719485411509)]
有任何问题,欢迎广大网友一起来交流