Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

mdjsxy111/AndroidHttpCapture

Repository files navigation

Android 应用内抓包

1、背景

平时开发及使用经常会遇到需要抓接口的情形,以往的抓包场景有两种:

  • 第一种是手机端连接电脑,电脑打开抓包工具,进行内部接口抓取,但此种方式需要设备、工具齐全,https请求还需要安装信任 证书,若身边没有电脑就无法操作;
  • 第二种是手机端安装抓包工具进行接口抓取,但抓包工具往往收费的比较多,使用免费或破解版又会担心数据安全问题。

为了使任何安装了APP设备在出现任何接口异常或者接口数据需要考证的时候,能及时抓取接口验证,因此就孕育而生应用内抓包的功能 模块的研究及开发。

2、设计思路

  • 需要有一个可控制是否抓包的开关
  • 接口请求列表,最好在列表上可以简单了解到一些信息,例如接口地址、请求状态(成功与否)、请求用时等
  • 接口请求详情,接口请求具体信息,包含请求地址、状态、参数、结果、错误信息
  • 搜索功能,可搜索特定的一批或一个接口
  • 排序功能,按请求时间正序或者倒序
  • 考虑到内存问题,默认缓存特定数量的接口请求,并且可以手动清除所有请求
  • 有个悬浮在窗口层的悬浮按钮,方便进入工具的展示及操作列表

3、设计实现

  • 抓包开关

    开启抓包时,抓包库内部对Android10以上系统动态申请android.permission.ACCESS_FINE_LOCATION

    权限配置,Android10及以上系统显示Wi-Fi名称,要动态申请android.permission.ACCESS_FINE_LOCATION

    <!-- 获取悬浮的权限 -->
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <!--网络状态-->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <!--wifi状态权限-->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <!--如果是安卓10.0,需要后台获取连接的wifi名称则添加进程获取位置信息权限 -->
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    <!--android 10.0使用wifi api新添加的权限 此权限需动态申请-->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    注册网络改变广播

    /**
     * 注册网络改变的广播
     */
    private void registerNetworkConnect() {
     IntentFilter filter = new IntentFilter();
     //监听wifi连接(手机与路由器之间的连接)
     filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
     //监听互联网连通性(也就是是否已经可以上网了),当然只是指wifi网络的范畴
     filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
     //这个是监听网络状态的,包括了wifi和移动网络。
     filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
     networkConnectChangedReceiver = new NetworkConnectChangedReceiver();
     context.registerReceiver(networkConnectChangedReceiver, filter);
    }
    /**
     * Wi-Fi改变的监听
     */
    public class NetworkConnectChangedReceiver extends BroadcastReceiver {
     @Override
     public void onReceive(Context context, Intent intent) {
     // 这个监听网络连接的设置,包括wifi和移动数据的打开和关闭。.
     if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
     NetworkInfo info = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
     if (info != null && info.isConnected()) {
     // 设置当前网络环境
     } else {
     // 设置没有网络
     }
     }
     }
    }
  • 获取接口数据

    举例okhttp3设置拦截器获取接口数据

    // 网络框架
    implementation 'com.squareup.okhttp3:okhttp:4.3.0'
    implementation 'com.lzy.net:okhttputils:1.8.1'

    添加拦截器

    OkHttpUtils.init(application);
    HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor("OkHttp");
    interceptor.setPrintLevel(HttpLoggingInterceptor.Level.BODY);//log打印级别,决定了log显示的详细程度
    interceptor.setColorLevel(Level.INFO);
    OkHttpUtils.getInstance().addInterceptor(interceptor);

    拦截器中获取接口数据

    接口地址url:

    url = request.url().toString();

    请求参数requestString:

    Request copy = request.newBuilder().build();
    RequestBody body = copy.body();
    if (body == null) return;
    Buffer buffer = new Buffer();
    body.writeTo(buffer);
    Charset charset = getCharset(body.contentType());
    requestString = buffer.readString(charset);

    请求状态code:

    Response.Builder builder = response.newBuilder();
    Response clone = builder.build();
    code = clone.code();

    请求时间dateStr:

    String dateStr = DateUtil.getString(new Date(), DateUtil.PATTERN_HMS);

    响应耗时tookMs:响应成功时间-发送请求时间

    long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);

    响应数据body:

    byte[] bytes = IOUtils.toByteArray(responseBody.byteStream());
    MediaType contentType = responseBody.contentType();
    body = new String(bytes, getCharset(contentType));
  • 存储接口数据

    将拦截器或网络基类中获取的接口数据添加到List中

    HttpCaptureData.getSingleton().create()// 创建CaptureData收集对象
     .setCaptureHost(host)// host域名
     .setCaptureStatus(status)// 接口状态
     .setCaptureDate(dateStr)// 请求时间
     .setCaptureTime(ms)// 请求时长
     .setCaptureUrl(debugUrl)// 请求地址
     .setCaptureRequestStr(requestStr)// 请求参数
     .setCaptureResponseStr(responseStr)// 响应结果
     .add();// 添加集合

    设置List线程安全

    httpCaptureList = Collections.synchronizedList(new ArrayList<>());

    设置最多存储200条数据

    List<CaptureInterfaceItemBean> captureList = HttpCaptureData.getSingleton().httpCaptureList;
    captureList.add(0, captureInterfaceItemBean);
    // 最多200条
    if (captureList.size() > 200) {
     captureList.remove(200);
    }
  • 显示接口数据

    将接口数据以Json格式显示

    // 判断是否为json数据
    if (JsonUtil.isJson(json)) {
     // 如果是json,就以json格式显示
     jsonObject = new JSONObject(json);
     tvJson.setText(jsonObject.toString(1));
    } else {
     tvJson.setText(json);
    }

    使用JsonView自定义控件,展示出Json 的结构,并可展开和缩起

    try {
     // 显示json数据
     JSONObject jsonObject = new JSONObject(jsonStr);
     jsonViewer.setJson(jsonObject);
     } catch (JSONException e) {
     e.printStackTrace();
     }
  • 分享接口数据

    将TextView设置android:textIsSelectable="true"后即可实现长按复制、分享功能

    <TextView
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:text=""
     android:textIsSelectable="true" />
  • 清理接口数据

    HttpCaptureData.getSingleton().httpCaptureList.clear();

4、Demo介绍

  • 开启调试入口

    开启后显示悬浮球,小球上会显示当前网络环境,Wi-Fi名称或移动网络。

    长按悬浮球进行网络切换(长按) 单击小球快捷进入代理抓包页面(单击)

  • 请求信息

    请求信息长按可复制,单击可显示Json结构,Json结构点击"{"可缩起

  • 清理请求信息

5、集成步骤

  • 导入依赖库

    implementation project(':httpcapturelibrary')
  • 初始化

    HttpCaptureManager.getInstance().init(this);
  • 在网络拦截器或网络请求基类中添加收集接口信息代码

    提示:网络拦截器收集信息时候需要注意response.body只能读取一次,多次使用报java.lang.IllegalStateException: closed,可以通过response.newBuilder()重新构建返回,来获取body。

    boolean isOpenCapture = HttpCaptureSPUtil.getIsOpenCapture();
    // 如果抓包开关打开后再进行数据获取
    if (isOpenCapture) {
    	HttpCaptureData.getSingleton().create()// 创建CaptureData收集对象
     .setCaptureHost(host)// host域名
     .setCaptureStatus(status)// 接口状态
     .setCaptureDate(dateStr)// 请求时间
     .setCaptureTime(ms)// 请求时长
     .setCaptureUrl(debugUrl)// 请求地址
     .setCaptureRequestStr(requestStr)// 请求参数
     .setCaptureResponseStr(responseStr)// 响应结果
     .add();// 添加集合
    }
  • 跳转抓包首页,开启抓包模式

    HttpCaptureHomeActivity.start(context);

About

Android APP内抓包工具

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

AltStyle によって変換されたページ (->オリジナル) /