Android 安全整改检测框架

背景

一、因工信部整改要求,现编写检测工具如下功能:

  • 1、禁止在用户未点击同意前,获取用户手机设备信息。
  • 2、禁止在用户未点击同意前,发起网络接口请求
  • 3、禁止在用户点击同意前,初始化第三方SDK,防止上报隐私信息;
  • 4、禁止调用获取软件安装列表等敏感android api接口;

二、集成步骤

1、在根项目的build.gradle中添加以下内容:

arduino 复制代码
dependencies {
    classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.8'
}

2、在需要使用module的build.gradle中添加(app则不用)

bash 复制代码
plugins {
    id 'android-aspectjx'
}

3、添加依赖

arduino 复制代码
dependencies {
    implementation "com.meiyou.aspectj:aspectj:1.2.0" //具体请参照update.md使用最新版本
}

4、注意(重要重要重要!!!!!!!!!!!!!!!)

必须实现IPrivacyPolicyStub中的方法:

kotlin 复制代码
@Protocol("PrivacyPolicyStub")
public class PrivacyPolicyStub {

    /**
     * 是否同意过首次进入app的隐私协议
     */
    public boolean isAcceptFirstStartApp() {
        return MainActivity.isAccepted;
    }
}

依赖包中会实时去获取isAcceptFirstStartApp()的值,当用户同意首次进入app的隐私协议后,需要及时改变返回的值。

5、确认主工程app/build.gradle有应用插件:

arduino 复制代码
apply plugin: 'android-aspectjx'
aspectjx {
 exclude 'com.alipay', 'com/alipay'
}
scss 复制代码
支付宝SDK必须exclude(不exclude会导致支付出现ClassNotFound),采用此种全局扫描,避免遗漏

6、如果原本自己的app有集成AspectjFix用于整改,对比一下这个库里边的AspectjUtil类,有重复的话,app里需要进行删除,避免重复hook造成的问题,因为这个库全局公用(重要重要重要!!!!!!!!!!!!!!!!!!!!)

三、测试方法

1、面向安全人员和产品的测试方法:

  • 1、下载fbflipper.com 工具,并打开,等待手机连接;
  • 2、安装美柚Test版本或者Debug版本(这两个版本有日志),手机USB连接电脑,连接成功后,Flippe软件会输出app的logcat日志
  • 3、在Flipper软件上过滤 "SAFE"字样
  • 4、操作APP,查看日志是否有异常即可,比如:

2、面向测试和开发人员的测试方法:

  • 可参考测试方法1或者按如下步骤

  • 1、编译Test或者Debug包(有日志就行)手机挂上Charles代理;

  • 2、操作以下过程:卸载重装app,打开app,停留隐私弹窗界面,点击隐私链接,然后返回停留在隐私弹窗界面。

  • 3、查看是否有触发 不符合安全整改 的问题(测试人员)

    • 查看对应项目的crash缺陷列表:

      • 出现"未接受隐私弹窗就初始化SDK"相关的字样的bug,需要进行修正,禁止在未同意前初始化第三方SDK
      • 出现 "获取了软件安装列表"相关的字样的bug,需要进行修正,禁止获取设备软件安装列表;
      • 出现 "用户未同意隐私协议,主线程获取设备信息:"相关的字样的bug,需要进行修正,用户未统一前,禁止获取设备信息
      • 出现 ""主线程接口请求""相关的字样的bug,需要进行修正,禁止在主线程进行网络请求
      • 出现 "application接口请求"相关的字样的bug,不一定需要进行修正,由开发进一步确认即可。
      • 若用户未点击同意前,代理出现http请求,请反馈开发进行修改,说明有遗漏拦截的地方
      • 若无以上问题,说明验证通过。
  • 4、查看是否有触发 不符合安全整改 的问题(开发人员)

    • 查看logcat信息日志,过滤"Aspect"字样:

      • 出现 "未接受隐私弹窗就初始化SDK"相关的字样的bug,需要进行修正,禁止在未同意前初始化第三方SDK
      • 出现 "获取了软件安装列表"相关的字样的bug,需要进行修正,禁止获取设备软件安装列表;
      • 出现 "用户未同意隐私协议,主线程获取设备信息:"相关的字样的bug,需要进行修正,用户未统一前,禁止获取设备信息
      • 出现 ""主线程接口请求""相关的字样的bug,需要进行修正,禁止在主线程进行网络请求
      • 出现 "application接口请求"相关的字样的bug,不一定需要进行修正,由开发进一步确认即可。
      • 若用户未点击同意前,代理出现http请求,需要进行修改,说明有遗漏拦截的地方
      • 若无以上问题,说明验证通过。
  • 5、 核心hook api如下:

`package com.meiyou.app.aspectj;

@Aspect public class AspectjUtil {

java 复制代码
public static final String TAG = "AspectjUtil";

/**
 * 第三方SDK包含:
 * 友盟、bugly、QQ、微博、微信、支付宝、
 * 淘宝百川、七鱼、腾讯IM、
 * 阿里云播放器、穿山甲、腾讯X5、
 * 阿里云、高德地图、OPPO PUSH、VIVIO PUSH、J PUSH、HUAWEI PUSH、MI PUSH、
 * 腾讯短视频;
 * 美摄SDK
 * @param joinPoint
 * @return
 * @throws Throwable
 */
@Around("(call(* com.baichuan.nb_trade.core.AlibcTradeSDK.asyncInit(..))) || " +    //百川sdk
        "(call(* com.tencent.smtt.sdk.QbSdk.initX5Environment(..))) || " +          //X5
        "(call(* com.meiyou.framework.ui.widgets.pulltorefreshview.CustomWebView.init(..))) || " + //X5 webview
        "(call(* com.tencent.bugly.crashreport.CrashReport.initCrashReport(..))) || " +            //Bugly
        "(call(* com.umeng.commonsdk.UMConfigure.init(..))) || " +      //友盟SDK
        "(call(* com.meiyou.framework.share.SocialService.prepare(..))) || " +  //分享SDK
        "(call(* com.qiyukf.unicorn.api.Unicorn.init(..))) || " +               //七鱼SDK
        "(call(* com.bytedance.sdk.openadsdk.TTAdSdk.init(..))) || " +          //穿山甲SDK
        "(call(* com.tencent.imsdk.TIMManager.init(..))) || " +                 //腾讯IM SDK
        "(call(* com.amap.api.location.AMapLocationClient.startLocation(..))) || " +  //高德SDK
        "(call(* com.meiyou.pushsdk.PushSDK.init(..))) || " +
        "(call(* com.tencent.ugc.TXUGCBase.setLicence(..))) || " +              //腾讯视频SDK
        "(call(* com.meicam.sdk.NvsStreamingContext.init(..))) " )
public Object handleSDKInit(ProceedingJoinPoint joinPoint) throws Throwable {
    try {
        if (!AspectjController.INSTANCE.isAcceptFirstStartApp()) {
            if(isTest()){
                //上报tapd,用于测试记录
                String line="",className="",methodName="";
                try {
                     line = joinPoint.getSourceLocation().toString();  //BbjInit:83
                      className = joinPoint.getSignature().getDeclaringType().getSimpleName();// TTTBASE
                     methodName = joinPoint.getSignature().getName(); //setLicence
                }catch (Exception ex){
                    ex.printStackTrace();
                }
                String message = "严重警告:未接受隐私弹窗就初始化SDK:"+line+"->"+className+"->"+methodName;
                LogUtils.e(TAG, message);
                ToastUtils.showToast(MeetyouFramework.getContext(), message);
                sendToTapd(message,3);
                if(isTest() && joinPoint.getTarget()!=null &&  joinPoint.getSignature()!=null){
                    //打印logcat,用于后台埋点
                    String name = joinPoint.getSignature().getName();
                    String classSimpleName =  joinPoint.getTarget().getClass().getSimpleName();
                    AspectjLogController.INSTANCE.handleThirdSDKReport(
                            classSimpleName,name,"");
                }
            }
        }
    } catch (Exception e) {
    }
    return joinPoint.proceed();
}

@Around("(call(* android.content.pm.PackageManager.getInstalledPackages(..))) || "+
        "(call(* android.content.pm.PackageManager.getInstalledPackagesAsUser(..))) || " +
        "(call(* android.content.pm.PackageManager.getInstalledApplications(..)))")
public Object handleGlobalGetInstalledPackages(ProceedingJoinPoint joinPoint) throws Throwable {
    try {
        //上报tapd,用于测试记录
        if(isTest()){
            String line="",className="",methodName="";
            try {
                line = joinPoint.getSourceLocation().toString();  //BbjInit:83
                className = joinPoint.getSignature().getDeclaringType().getSimpleName();// TTTBASE
                methodName = joinPoint.getSignature().getName(); //setLicence
            }catch (Exception ex){
                ex.printStackTrace();
            }
            String message = "严重警告:获取了软件安装列表:"+line+"->"+className+"->"+methodName;
            LogUtils.e(TAG, message);
            ToastUtils.showToast(MeetyouFramework.getContext(), message);
            sendToTapd(message,3);
        }

        //打印logcat,用于后台埋点
        try {
            if(isTest()&& joinPoint.getTarget()!=null &&  joinPoint.getSignature()!=null){
                String name = joinPoint.getSignature().getName();
                String classSimpleName =  joinPoint.getTarget().getClass().getSimpleName();
                AspectjLogController.INSTANCE.handleLogReport(classSimpleName,name,"");
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }
        return joinPoint.proceed();
    } catch (Exception e) {
    }
    return null;
}

@Around("call(* android.content.Context.getSystemService(..))")
public Object location(ProceedingJoinPoint joinPoint) throws Throwable {
    try {
        Object[] args = joinPoint.getArgs();
        if(args!=null && isTest()){
            for (Object arg : args) {
                if (StringUtils.equalsIgnoreCase("location",arg.toString())) {
                    LogUtils.d(TAG, "arg = " + arg.toString());
                    String className = joinPoint.getSignature().getName();
                    LogUtils.e(TAG, "className = " + className);
                    LogUtils.e(TAG, "获取了用户的位置信息");
                    String message = Log.getStackTraceString(new Throwable());
                    AspectjLogController.INSTANCE.handleLocationReport(className,className,message);
                    LogUtils.d(TAG,message);
                }
            }
        }
        return joinPoint.proceed();//joinPoint.proceed();
    } catch (Exception e) {
        //e.printStackTrace();
    }
    return null;
}

@Around("(call(* com.amap.api.location.AMapLocationClient.startLocation(..))) ")
public Object handleGlobalLocation(ProceedingJoinPoint joinPoint) throws Throwable {
    try {
        //打印logcat,用于后台埋点
        if(isTest()&& joinPoint.getTarget()!=null &&  joinPoint.getSignature()!=null){
            String name = joinPoint.getSignature().getName();
            String classSimpleName =  joinPoint.getTarget().getClass().getSimpleName();
            AspectjLogController.INSTANCE.handleLocationReport(classSimpleName,name,"");
        }
    }catch (Exception ex){
        ex.printStackTrace();
    }
    return joinPoint.proceed();
}
@Around("(call(* android.content.ContentResolver.query(..))) ")
public Object handleGlobalContentResolver(ProceedingJoinPoint joinPoint) throws Throwable {
    try {
        try {
            if(isTest()&& joinPoint.getTarget()!=null &&  joinPoint.getSignature()!=null){
                String arg0 = null;
                if(joinPoint.getArgs()!=null && joinPoint.getArgs().length>0){
                    arg0 = joinPoint.getArgs()[0].toString();//content://call_log/calls
                }
                String name = joinPoint.getSignature().getName();
                String classSimpleName =  joinPoint.getTarget().getClass().getSimpleName();
                AspectjLogController.INSTANCE.handleContentProviderReport(arg0,classSimpleName,name,"");
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }
        return joinPoint.proceed();
    } catch (Exception e) {
    }
    return null;
}

/**
 * 禁止百川SDK获取应用列表
 * @param joinPoint
 * @return
 * @throws Throwable
 */
@Around("call(* com.alibaba.alibclinkpartner.smartlink.manager.ALSLAppCheckManager.getInstallAppList(..))")
public Object handleBaichuanGetInstalledPacakges(ProceedingJoinPoint joinPoint) throws Throwable {
    try {
        LogUtils.e(TAG,"捕获到百川获取应用列表,拦截它并反馈new ArrayList()");
        return new ArrayList<>();
    } catch (Exception e) {
    }
    return null;
}

//@Around("call(* android.app.ActivityManager.getRunningAppProcesses(..))")
@Around("execution(* com.alibaba.analytics.a.a.c())")
public Object handleAlibabaGetRunningAppProcess(ProceedingJoinPoint joinPoint) {
    try {
        //禁用百川定频获取,强制返回前后台标识;
        /*
        if(isHitForbiddenMethod(joinPoint,"getRunningAppProcesses","ActivityManager","com.alibaba.analytics")){
            return null;
        }
        return joinPoint.proceed();*/
        return MeetyouWatcher.getInstance().getAppFrontBackWatcher().isAppAtBg();
    }catch (Exception ex){
        ex.printStackTrace();
    } catch (Throwable throwable) {
        //throwable.printStackTrace();
    }
    return false;
}

private boolean isAppAtBg(){
    if(MeetyouWatcher.getInstance().getAppFrontBackWatcher()!=null
            && MeetyouWatcher.getInstance().getAppFrontBackWatcher().isAppAtBgMemory()){
        return true;
    }
    return false;
}
/**
 * AndroidQ适配
 * 修复友盟android 10 因为权限无法上报的问题;
 * <p>
 * 以及 工信部整改需求:未点击同意前,不允许获取设备信息
 * * https://www.tapd.cn/21039721/prong/stories/view/1121039721001042893
 * * @param joinPoint
 *
 * @param joinPoint
 * @return
 * @throws Throwable
 */
@Around("(call(* android.telephony.TelephonyManager.*(..))) || " +
        "(call(* android.net.wifi.WifiInfo.*(..))) || " +
        "(call(* java.net.NetworkInterface.getHardwareAddress*(..))) || " +
        "(call(* com.meiyou.sdk.core.UniqueIdUtils.getDeviceInfo(..))) || " +
        "(call(* com.meiyou.sdk.core.DeviceUtils.getProvidersIMSI(..))) || " +
        "(call(* com.meiyou.sdk.core.DeviceUtils.getPhoneOnlyKey(..))) || " +
        "(call(* com.meiyou.detector.functionlality.Telephony.getImei(..))) || " +
        "(call(* com.meiyou.detector.functionlality.Telephony.getImeiX(..))) || " +
        "(call(* com.meiyou.detector.functionlality.Telephony.getImsi(..))) || " +
        "(call(* com.meiyou.detector.functionlality.Telephony.getNetworkOperator(..))) || " +
        "(call(* com.meiyou.detector.functionlality.Telephony.getSimStatus(..))) || " +
        "(call(* com.meiyou.detector.functionlality.Telephony.getPhoneNumber(..))) || " +
        "(call(* com.umeng.commonsdk.statistics.common.DeviceConfig.getAndroidId(..))) || " +
        "(call(* com.umeng.commonsdk.statistics.common.DeviceConfig.getCPU(..))) || " +
        "(call(* com.umeng.commonsdk.statistics.common.DeviceConfig.getDeviceIdForGeneral(..))) || " +
        "(call(* com.umeng.commonsdk.statistics.common.DeviceConfig.getDeviceIdForBox(..))) || " +
        "(call(* com.umeng.commonsdk.statistics.common.DeviceConfig.getGPU(..))) || " +
        "(call(* com.umeng.commonsdk.statistics.common.DeviceConfig.getImei(..))) || " +
        "(call(* com.umeng.commonsdk.statistics.common.DeviceConfig.getIMEI(..))) || " +
        "(call(* com.umeng.commonsdk.statistics.common.DeviceConfig.getImeiNew(..))) || " +
        "(call(* com.umeng.commonsdk.statistics.common.DeviceConfig.getImsi(..))) || " +
        "(call(* com.umeng.commonsdk.statistics.common.DeviceConfig.getMacBySystemInterface(..))) || " +
        "(call(* com.umeng.commonsdk.statistics.common.DeviceConfig.getMacByJavaAPI(..))) || " +
        "(call(* com.umeng.commonsdk.statistics.common.DeviceConfig.getMacShell(..))) || " +
        "(call(* com.meiyou.common.apm.controller.ApmAgent.start(..))) || " +
        "(call(* com.meiyou.detector.DetectorManager.getDetectionInfoWithSign(..))) || " +
        "(call(* com.meiyou.framework.util.ChannelUtil.getStatisticInfo(..)))")
public Object handleGlobalGetDeviceInfo(ProceedingJoinPoint joinPoint) {
    try {


        //android 10无法获取imei
        if(Build.VERSION.SDK_INT >= 29 ){
            if(isHitForbiddenMethod(joinPoint,"getDeviceId","TelephonyManager","")){
                return null;
            }
        }
        //禁止小米SDK在后台的时候获取SSID
        if(isHitForbiddenMethodWhenBg(joinPoint,"getSSID","WifiInfo","com.xiaomi.push")){
            return null;
        }
        //禁止七鱼SDK在后台的时候获取IMEI
        if(isHitForbiddenMethodWhenBg(joinPoint,"getDeviceId","TelephonyManager","com.qiyukf")){
            return null;
        }

        if (!AspectjController.INSTANCE.isAcceptFirstStartApp()) {
            if (Thread.currentThread() != Looper.getMainLooper().getThread()) {
                LogUtils.e(TAG, "线程中获取设备信息,因用户未同意隐私协议,已被拦截等待");
                while (true) {
                    Thread.sleep(50);
                    if (AspectjController.INSTANCE.isAcceptFirstStartApp()) {
                        break;
                    }
                }
                LogUtils.e(TAG, "线程中用户已同意隐私协议,释放拦截");
            } else {
                if (joinPoint.getSourceLocation().toString().contains("AppUtil")) {
                    return null;
                }
                try {
                    if (isTest()) {
                        String line="",className="",methodName="";
                        try {
                            line = joinPoint.getSourceLocation().toString();  //BbjInit:83
                            className = joinPoint.getSignature().getDeclaringType().getSimpleName();// TTTBASE
                            methodName = joinPoint.getSignature().getName(); //setLicence
                        }catch (Exception ex){
                            ex.printStackTrace();
                        }
                        String message = "严重警告:用户未同意隐私协议,主线程获取设备信息:"+line+"->"+className+"->"+methodName;
                        LogUtils.e(TAG, message);
                        ToastUtils.showToast(MeetyouFramework.getContext(), message);
                        sendToTapd(message,3);
                    }
                }catch (Exception ex){
                    ex.printStackTrace();
                }
                try {
                    if(isTest() && joinPoint.getTarget()!=null && joinPoint.getSignature()!=null){
                        String name = joinPoint.getSignature().getName();
                        String classSimpleName =  joinPoint.getTarget().getClass().getSimpleName();
                        AspectjLogController.INSTANCE.handleLogReport(classSimpleName,name,"");
                    }
                }catch (Exception ex){
                    ex.printStackTrace();
                }
            }
        } else {
            LogUtils.i(TAG, "用户已同意隐私协议,可正常获取设备信息");
            try {
                if(isAppAtBg()  && joinPoint.getSignature()!=null){
                    String name = joinPoint.getSignature().getName();
                    String classSimpleName = "";
                    if(joinPoint.getTarget()!=null){
                        classSimpleName = joinPoint.getTarget().getClass().getSimpleName();
                    }
                    if(AspectjLogController.INSTANCE.isHitDeviceInfo(name+"",classSimpleName+"")){
                        LogUtils.i(TAG,"后台命中获取设备信息methodname:"+name+" className:"+classSimpleName+" 返回null");
                        return null;
                    }
                }
                if(isTest() && joinPoint.getTarget()!=null && joinPoint.getSignature()!=null){
                    String name = joinPoint.getSignature().getName();
                    String classSimpleName =  joinPoint.getTarget().getClass().getSimpleName();
                    AspectjLogController.INSTANCE.handleLogReport(classSimpleName,name,"");
                }
            }catch (Exception ex){
                ex.printStackTrace();
            }
        }
        return joinPoint.proceed();
    } catch (Exception e) {
        //e.printStackTrace();
    } catch (Throwable throwable) {
        //throwable.printStackTrace();
    }
    return null;
}

private boolean isHitForbiddenMethod(ProceedingJoinPoint joinPoint,String methodName,String classsimpleName,String stack){
    try {
        try {
            if(joinPoint.getTarget()!=null && joinPoint.getSignature()!=null){
                String name = joinPoint.getSignature().getName();
                String classSimpleName =  joinPoint.getTarget().getClass().getSimpleName();
                if(StringUtils.isNull(methodName)){
                    if((classsimpleName.equalsIgnoreCase(classSimpleName))){
                        if(StringUtils.isNull(stack)){
                            return true;
                        }
                        if(getStackLog().contains(stack)){
                            LogUtils.e(TAG,"禁用"+stack+"获取获取设备信息:"+methodName+" 直接return "+classSimpleName);
                            return true;
                        }
                    }
                }else{
                    if((methodName.equalsIgnoreCase(name) && classsimpleName.equalsIgnoreCase(classSimpleName))){
                        if(StringUtils.isNull(stack)){
                            return true;
                        }
                        if(getStackLog().contains(stack)){
                            LogUtils.e(TAG,"禁用"+stack+"获取获取设备信息:"+methodName+" 直接return "+classSimpleName);
                            return true;
                        }
                    }
                }

            }
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }catch (Exception ex){
        ex.printStackTrace();
    }
    return false;
}

private boolean isHitForbiddenMethodWhenBg(ProceedingJoinPoint joinPoint,String methodName,String classsimpleName,String stack){
    try {
        try {
            if(MeetyouWatcher.getInstance().getAppFrontBackWatcher()!=null
                    && MeetyouWatcher.getInstance().getAppFrontBackWatcher().isAppAtBgMemory()
                    &&  joinPoint.getTarget()!=null && joinPoint.getSignature()!=null){
                String name = joinPoint.getSignature().getName();
                String classSimpleName =  joinPoint.getTarget().getClass().getSimpleName();
                if(StringUtils.isNull(methodName)){
                    if((classsimpleName.equalsIgnoreCase(classSimpleName))){
                        if(getStackLog().contains(stack)){
                            LogUtils.e(TAG,"在后台时,禁用"+stack+"获取获取设备信息:"+methodName+" 直接return "+classSimpleName);
                            return true;
                        }
                    }
                }else{
                    if((methodName.equalsIgnoreCase(name) && classsimpleName.equalsIgnoreCase(classSimpleName))){
                        if(getStackLog().contains(stack)){
                            LogUtils.e(TAG,"在后台时,禁用"+stack+"获取获取设备信息:"+methodName+" 直接return "+classSimpleName);
                            return true;
                        }
                    }
                }

            }
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }catch (Exception ex){
        ex.printStackTrace();
    }
    return false;
}

@Around("(execution(*  com.tencent.smtt.utils.b.d(..))) || " +
        "(execution(*  com.tencent.smtt.utils.b.f(..))) || " +
        "(execution(*  com.tencent.smtt.utils.b.e(..))) || " +
        "(execution(*  com.tencent.smtt.utils.b.g(..)))")
public Object handleX5GetDeviceInfo(ProceedingJoinPoint joinPoint) throws Throwable {
    try {
        if (!AspectjController.INSTANCE.isAcceptFirstStartApp()) {
            LogUtils.e(TAG, "用户未同意隐私协议,禁止com.tencent.smtt等方法执行获取设备信息");
            return null;
        } else {
            return joinPoint.proceed();
        }
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return joinPoint.proceed();
}

/**
 * 工信部整改需求:未同意前,不允许请求网络
 * https://www.tapd.cn/21039721/prong/stories/view/1121039721001042893
 *
 * @param joinPoint
 * @throws Throwable
 */
@Around("(call(* okhttp3.OkHttpClient.newCall(..))) || (call(* okhttp3.Call.execute(..)))")
public Object handleOkHttp(ProceedingJoinPoint joinPoint) throws Throwable {
    try {
        if (!AspectjController.INSTANCE.isAcceptFirstStartApp()) {
            if (Thread.currentThread() != Looper.getMainLooper().getThread()) {
                LogUtils.e(TAG, "线程中触发接口,因用户未同意隐私协议,已被拦截等待");
                while (true) {
                    Thread.sleep(50);
                    if (AspectjController.INSTANCE.isAcceptFirstStartApp()) {
                        break;
                    }
                }
                LogUtils.e(TAG, "用户已同意隐私协议,释放拦截接口等待");
            }
        } else {
            LogUtils.i(TAG, "用户已同意隐私协议,可正常进行网络请求");
        }
        //不是正式包,但是正式环境
        if(!AspectjController.INSTANCE.isProductApk()){
            if(isTest()){
                String url = getRequestUrl(joinPoint);
                if(!StringUtils.isNull(url) && url.contains("test-") || url.contains("yf-")){
                    //正式环境请求了test-
                    try {
                        AspectjLogController.INSTANCE.handleHttpWrongReport("","",url);
                    }catch (Exception ex){
                        ex.printStackTrace();
                    }
                }
            }
        }
        if(isTest()){
            final String url = getRequestUrl(joinPoint);
            try {
                    AspectjLogController.INSTANCE.handleHttpReport("","",url);
            }catch (Exception ex){
                ex.printStackTrace();
            }

            //检测主线程http请求
            /*if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
                if (!AspectjController.INSTANCE.isWhiteUrl(url)
                         && !url.contains("doraemon.xiaojukeji.com")) {
                    // 解析请求地址
                    if (!StringUtils.isNull(url)) {
                        Uri uri = Uri.parse(url);
                        String message = uri.getPath()+ ":主线程接口请求:"+url;
                        LogUtils.e(TAG, message);
                        ToastUtils.showToast(MeetyouFramework.getContext(), message);
                        sendToTapd(message,3);
                    }
                }
            }*/
            //检测application 里的网络请求
            if(AspectjController.INSTANCE.isReportApplicationHttp()){
                if (!AspectjController.INSTANCE.isWhiteUrl(url)&& !url.contains("doraemon.xiaojukeji.com")) {
                    if (MeetyouWatcher.getInstance().getActvityWatcher()!=null
                            && MeetyouWatcher.getInstance().getActvityWatcher().getTopActivity()==null) {
                        new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                if (MeetyouWatcher.getInstance().getActvityWatcher()!=null && MeetyouWatcher.getInstance().getActvityWatcher().getTopActivity()==null) {
                                    if (!StringUtils.isNull(url)) {
                                        Uri uri = Uri.parse(url);
                                        String urlLog = uri.getScheme()+"://"+uri.getHost()+uri.getPath();//放服务端虑重,移除query
                                        String message = uri.getPath()+ ":application接口请求:"+urlLog;
                                        sendToTapd(message, 3);
                                    }
                                }
                            }
                        },1000);
                    }
                }
            }
        }
        return joinPoint.proceed();
    } catch (Exception e) {
        // e.printStackTrace();
    } catch (Throwable throwable) {
        // throwable.printStackTrace();
    }
    return null;
}


/**
 * 解析获取请求地址
 */
public String getRequestUrl(ProceedingJoinPoint joinPoint) {
    String url = "";
    try {
        if (joinPoint != null && joinPoint.getTarget() != null) {
            if (joinPoint.getTarget() instanceof Call) {
                Call call = (Call) joinPoint.getTarget();
                url = call.request().url().toString();
                LogUtils.i(TAG, "Call url=" + url);
            }
            if (joinPoint.getTarget() instanceof OkHttpClient) {
                if (joinPoint.getArgs() != null
                        && joinPoint.getArgs().length > 0
                        && joinPoint.getArgs()[0] instanceof Request) {
                    url = ((Request) joinPoint.getArgs()[0]).url().toString();
                    LogUtils.i(TAG, "OkHttpClient url=" + url);
                }
            }
        }
    } catch (Exception e) {
    }
    return url;
}

/**
 * 发送到tapd
 */
public void sendToTapd(String errorMsg, int infoType) {
    try {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("errorMsg", errorMsg);
        jsonObject.put("stack", getStackLog());
        AspectjController.INSTANCE.sendToTapd(jsonObject.toString(), infoType);
    } catch (Exception e) {

    }
}

private String  getStackLog(){
    try {
        String str = Log.getStackTraceString(new Throwable());
        if(str.length()>800){
            return str.substring(0,800);
        }else{
            return str;
        }
    }catch (Exception ex){
        ex.printStackTrace();
    }

    return "";
}

private boolean isTest() {
    return ConfigManager.from(MeetyouFramework.getContext()).isDebug()
            || ConfigManager.from(MeetyouFramework.getContext()).isTest();
}

} `

参考资料

相关推荐
_.Switch1 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光1 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   1 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   1 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web1 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
安冬的码畜日常1 小时前
【CSS in Depth 2 精译_044】第七章 响应式设计概述
前端·css·css3·html5·响应式设计·响应式
莹雨潇潇2 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
Jiaberrr2 小时前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui
Tiffany_Ho3 小时前
【TypeScript】知识点梳理(三)
前端·typescript
安冬的码畜日常4 小时前
【D3.js in Action 3 精译_029】3.5 给 D3 条形图加注图表标签(上)
开发语言·前端·javascript·信息可视化·数据可视化·d3.js