├── .gitignore ├── LICENSE ├── README-EN.md ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── apminsightdemo │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── apminsightdemo │ │ │ ├── App.java │ │ │ ├── BlockListActivity.java │ │ │ ├── FirstActivity.java │ │ │ ├── HybridTestActivity.java │ │ │ ├── MainActivity.java │ │ │ └── fragment │ │ │ └── ListFragment.java │ └── res │ │ ├── layout │ │ ├── activity_block_list.xml │ │ ├── activity_hybrid_main.xml │ │ ├── activity_main.xml │ │ └── item_block_scrolling.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── example │ └── apminsightdemo │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | .idea 4 | /local.properties 5 | /.idea/caches 6 | /.idea/libraries 7 | /.idea/modules.xml 8 | /.idea/workspace.xml 9 | /.idea/navEditor.xml 10 | /.idea/assetWizardSettings.xml 11 | .DS_Store 12 | /build 13 | /captures 14 | .externalNativeBuild 15 | .cxx 16 | /.idea/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Volcengine 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README-EN.md: -------------------------------------------------------------------------------- 1 | [中文版本](README.md) 2 | # APMPlusDemo 3 | This is an example of APMPlus SDK. Enter official website to read the introduction of SDK capabilities and access. 4 | 1. [APMPlus Android Official Website](https://www.volcengine.com/docs/6431/68852) 5 | 2. [APMPlus Android Q&A](https://www.volcengine.com/docs/6431/127838) 6 | 7 | ### Usage 8 | 1. The demo APP has integrated all capabilities of APMPlus. 9 | 2. You can make errors and performance data in the demo APP. 10 | 3. The data is shown on APMPlus. 11 | #### Request for access to demo data 12 | * Register an account for APMPlus. [Go to Register](https://www.volcengine.com/products/apmplus) 13 | 14 | ### License 15 | APMPlus_Android is available under the MIT license. See the [LICENSE](LICENSE) file for more info. 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [ENGLISH](README-EN.md) 2 | # APMPlusDemo 3 | 这是 APMPlus Sdk的使用示例. 下面链接有详细的Sdk接入和使用说明 4 | 1. [APMPlus Android 接入文档](https://www.volcengine.com/docs/6431/68852) 5 | 2. [APMPlus Android Q&A](https://www.volcengine.com/docs/6431/127838) 6 | 7 | ### Demo使用说明 8 | 1. 这个demo已经接入了所有APMPlus的性能和稳定性监控的能力。 9 | 2. 可以在这个demo里面模拟异常和性能数据收集上报。 10 | 3. 数据会上报到APMPlus平台,可以配置成自己项目的Aid进行SDK功能测试。 11 | #### 注册并查看demo上报的数据 12 | 1. 在APMPlus平台注册一个账号。[注册地址](https://www.volcengine.com/products/apmplus) 13 | 2. 然后修改demo里的Aid进行测试。 14 | ### 开源许可协议 15 | APMPlus_Android 使用 MIT 协议,具体内容查看 [LICENSE](LICENSE) 16 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'apm-plugin' 3 | 4 | 5 | android { 6 | compileSdkVersion 34 7 | buildToolsVersion "29.0.3" 8 | 9 | defaultConfig { 10 | applicationId "com.example.apminsightdemo" 11 | minSdkVersion 18 12 | targetSdkVersion 34 13 | versionCode 1 14 | versionName "1.0" 15 | 16 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 17 | 18 | manifestPlaceholders.put("APPLOG_SCHEME", "insight".toLowerCase()) 19 | 20 | } 21 | 22 | buildTypes { 23 | release { 24 | minifyEnabled false 25 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 26 | } 27 | } 28 | compileOptions { 29 | sourceCompatibility 1.8 30 | targetCompatibility 1.8 31 | } 32 | } 33 | 34 | dependencies { 35 | implementation fileTree(dir: 'libs', include: ['*.jar']) 36 | 37 | //apm性能组件 38 | implementation 'com.volcengine:apm_insight:1.5.3.cn' 39 | //apm稳定性组件 40 | implementation 'com.volcengine:apm_insight_crash:1.5.0' 41 | 42 | implementation "com.squareup.okhttp3:okhttp:3.14.0" 43 | 44 | implementation 'com.android.support:appcompat-v7:28.0.0' 45 | implementation 'com.android.support:recyclerview-v7:28.0.0' 46 | testImplementation 'junit:junit:4.12' 47 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 48 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 49 | 50 | } 51 | 52 | ApmPlugin { 53 | // 是否进行插桩 54 | enable true 55 | // 是否在Debug包插桩,默认插桩 56 | enableInDebug true 57 | // DEBUG("DEBUG"), INFO("INFO"), WARN("WARN"), ERROR("ERROR"); 58 | // INFO 级别Log会汇总所有被插桩处理的类供查看,路径 app/build/ByteX/ApmPlugin 59 | logLevel "DEBUG" 60 | // 监控App启动耗时,需要同时开启pageLoadSwitch 61 | startSwitch = true 62 | // 监控Activity的生命周期耗时 63 | pageLoadSwitch = true 64 | // 监控okhttp3的网络请求 65 | okHttp3Switch = true 66 | // 只对白名单下的包进行插桩。可以填写自己的包名。不配置则不会插桩,影响网络监控也启动监控等功能。 67 | whiteList = [ 68 | "com" 69 | ] 70 | // 黑名单包下类不进行插桩,可以配置包名和类名。没有可以为空 71 | blackList = [ 72 | ] 73 | } 74 | 75 | 76 | apply from: 'https://lf-apmplus.volccdn.com/obj/apminsight-symbolicate/apminsight.gradle' 77 | apminsightConfig { 78 | api_token = "" // 从平台的 全部功能->符号表管理->系统选择 Android->下面可以看到api key和api token。或者联系开发同学获取到的对应appId的一个token,私有化部署不用填 79 | api_key = 0 // 从平台的 全部功能->符号表管理->系统选择 Android->下面可以看到api key和api token。或者联系开发同学获取到的对应appId的一个key,私有化部署不用填 80 | aid = 187277 // 平台上的appid 81 | // update_version_code = -1 // 默认不用写这一行, 除非你初始化时候手动指定了非标准版本号(或SDK版本号); 此处一定要与apmInsight初始化的版本号一致 82 | // mappingUrl = "https://www.xxx.com" // 默认不用写这一行,如果是私有化,这里配置私有化域名 83 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/apminsightdemo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.example.apminsightdemo; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 23 | 24 | assertEquals("com.example.apminsightdemo", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 16 | 17 | 20 | 21 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/apminsightdemo/App.java: -------------------------------------------------------------------------------- 1 | package com.example.apminsightdemo; 2 | 3 | import android.app.Activity; 4 | import android.app.Application; 5 | import android.util.Log; 6 | 7 | import com.apm.insight.ExitType; 8 | import com.apm.insight.MonitorCrash; 9 | import com.apm.insight.log.VLog; 10 | import com.bytedance.apm.insight.ApmInsight; 11 | import com.bytedance.apm.insight.ApmInsightInitConfig; 12 | import com.bytedance.apm.insight.IActivityLeakListener; 13 | import com.bytedance.apm.insight.IDynamicParams; 14 | 15 | 16 | /** 17 | * Application 18 | * 19 | * @author steven 20 | * @date 2020/11/11 21 | */ 22 | public class App extends Application { 23 | public static String sSDKAid = "187277"; 24 | public static String sToken = "token"; 25 | public static String did = "device_id"; 26 | public static String uid = "user_id"; 27 | 28 | public static MonitorCrash mMonitorCrash; 29 | private static boolean hasStart; 30 | private static boolean hasInit; 31 | 32 | @Override 33 | public void onCreate() { 34 | super.onCreate(); 35 | initMonitor(this); 36 | } 37 | 38 | /** 39 | * 初始化APM监控,不会立即采集数据,需要放到Application的onCreate执行 40 | * 41 | * @param application 42 | */ 43 | private void initMonitor(Application application) { 44 | if (hasInit) { 45 | return; 46 | } 47 | hasInit = true; 48 | initCrash(application); 49 | initApmInsight(application); 50 | } 51 | 52 | /** 53 | * 崩溃监控初始化 54 | */ 55 | public static void initCrash(Application application) { 56 | MonitorCrash.Config config = MonitorCrash.Config.app(sSDKAid) 57 | .token(sToken)// 设置鉴权token,可从平台应用信息处获取,token错误无法上报数据 58 | // .versionCode(1)// 可选,默认取PackageInfo中的versionCode 59 | // .versionName("1.0")// 可选,默认取PackageInfo中的versionName 60 | // .channel("test")// 可选,设置App发布渠道,在平台可以筛选 61 | // .url("www.xxx.com")// 默认不需要,私有化部署才配置上报地址 62 | //可选,可以设置自定义did,不设置会使用内部默认的 63 | .dynamicParams(new MonitorCrash.Config.IDynamicParams() { 64 | @Override 65 | public String getDid() {//返回空会使用内部默认的did 66 | return did; 67 | } 68 | 69 | @Override 70 | public String getUserId() { 71 | return uid; 72 | } 73 | }) 74 | //可选,添加业务自定义数据,在崩溃详情页展示 75 | // .customData(crashType -> { 76 | // HashMap map = new HashMap<>(); 77 | // map.put("app_custom", "app_value"); 78 | // return map; 79 | // }) 80 | .exitType(ExitType.EXCEPTION) //上报应用退出原因,EXCEPTION会过滤USER_REQUEST类型 81 | .enableApmPlusLog(true) // 是否将崩溃信息等写入APMPlus日志,默认false 82 | // .crashProtect(true) //是否开启崩溃防护,默认true 83 | .autoStart(false) // 是否在初始化时自动开启监控,默认为true 84 | // .debugMode(true) //线下使用的日志开关,线上不要调用或设置为false 85 | // 可选,添加pv事件的自定义tag,可以用来筛选崩溃率计算的分母数据 86 | //.pageViewTags(<>>) 87 | .build(); 88 | mMonitorCrash = MonitorCrash.init(application, config); 89 | } 90 | 91 | /** 92 | * 性能监控初始化 93 | */ 94 | public static void initApmInsight(Application application) { 95 | //必须放到Application的onCreate里面,会注册监听生命周期,不涉及数据采集和隐私合规问题 96 | ApmInsight.getInstance().init(application); 97 | //初始化自定日志,配置自定义日志最大占用磁盘,内部一般配置20,代表最大20M磁盘占用。1.4.1版本开始存在这个api 98 | VLog.init(application, 20); 99 | } 100 | 101 | /** 102 | * 启动APM监控,在隐私合规后调用,开始采集数据 103 | */ 104 | public static void startMonitor(Application application) { 105 | if (hasStart) { 106 | return; 107 | } 108 | hasStart = true; 109 | 110 | // 如果初始化崩溃组件时未设置autoStart参数或者设置为true,将自动开启监控,不需要调用start方法。 111 | if (mMonitorCrash != null) { 112 | mMonitorCrash.start(); 113 | } 114 | 115 | //在同意隐私合规后调用,启动性能组件监控 116 | ApmInsightInitConfig.Builder builder = ApmInsightInitConfig.builder(); 117 | //必填:设置分配的appid 118 | builder.aid(sSDKAid); 119 | //必填:设置平台的app_token 120 | builder.token(sToken); 121 | //是否开启卡顿功能 122 | builder.blockDetect(true); 123 | //是否开启严重卡顿功能 124 | builder.seriousBlockDetect(true); 125 | //是否开启流畅性和丢帧 126 | builder.fpsMonitor(true); 127 | //控制是否打开WebVeiw监控 128 | builder.enableHybridMonitor(true); 129 | //控制是否打开内存监控 130 | builder.memoryMonitor(true); 131 | //控制是否打开电量监控 132 | builder.batteryMonitor(true); 133 | //是否打印日志,注:线上release版本要配置为false 134 | builder.debugMode(true); 135 | //支持用户自定义user_id把平台数据和自己用户关联起来,可以不配置。1.4.5版本后使用setDynamicParams()方法通过getUserId()回调设置 136 | // builder.userId("user_id"); 137 | //私有化部署:配置数据上报的域名 (私有化部署才需要配置,内部有默认域名),测试支持设置http://www.xxx.com 默认是https协议 138 | // builder.defaultReportDomain("www.xxx.com"); 139 | //设置渠道。1.3.16版本增加接口 140 | builder.channel("google play"); 141 | //打开自定义日志回捞能力,1.4.1版本新增接口 142 | builder.enableLogRecovery(true); 143 | //控制是否打开cpu监控能力 144 | builder.cpuMonitor(true); 145 | //打开磁盘监控 146 | builder.diskMonitor(true); 147 | //打开流量监控 148 | builder.trafficMonitor(true); 149 | //控制是否打开用户使用时长的监控 150 | builder.operateMonitor(true); 151 | //控制是否打开启动监控,开启需要同时配置apm-plugin插件 152 | builder.startMonitor(true); 153 | //控制是否打开页面Activity耗时监控,开启需要同时配置apm-plugin插件 154 | builder.pageMonitor(true); 155 | //控制是否打开网络监控,开启需要同时配置apm-plugin插件 156 | builder.netMonitor(true); 157 | //打开APMPlus日志能力,可以通过回捞获取APMPlus日志 158 | builder.enableAPMPlusLocalLog(true); 159 | builder.detectActivityLeak(new IActivityLeakListener() { 160 | @Override 161 | public void onActivityLeaked(Activity activity) { 162 | Log.e("Activity Leak", activity.getLocalClassName()); 163 | } 164 | }); 165 | //设置数据和Rangers Applog数据打通,设备标识did必填。1.3.16版本增加接口 166 | builder.setDynamicParams(new IDynamicParams() { 167 | @Override 168 | public String getUserUniqueID() { 169 | //可选。依赖AppLog可以通过AppLog.getUserUniqueID()获取,否则可以返回null。 170 | return null; 171 | } 172 | 173 | @Override 174 | public String getAbSdkVersion() { 175 | //可选。如果依赖AppLog可以通过AppLog.getAbSdkVersion()获取,否则可以返回null。 176 | return null; 177 | } 178 | 179 | @Override 180 | public String getSsid() { 181 | //可选。依赖AppLog可以通过AppLog.getSsid()获取,否则可以返回null。 182 | return null; 183 | } 184 | 185 | @Override 186 | public String getDid() { 187 | //1.4.0版本及以上,可选,其他版本必填。设备的唯一标识,如果依赖AppLog可以通过 AppLog.getDid() 获取,也可以自己生成。 188 | return did; 189 | } 190 | 191 | @Override 192 | public String getUserId() { 193 | //1.4.5.cn版本增加的接口 194 | return uid; 195 | } 196 | }); 197 | ApmInsight.getInstance().start(builder.build()); 198 | } 199 | 200 | } 201 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/apminsightdemo/BlockListActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.apminsightdemo; 2 | 3 | import android.os.Build; 4 | import android.os.Bundle; 5 | import android.support.annotation.NonNull; 6 | import android.support.annotation.RequiresApi; 7 | import android.support.v4.app.FragmentActivity; 8 | import android.support.v7.widget.LinearLayoutManager; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.widget.TextView; 14 | 15 | import java.util.ArrayList; 16 | 17 | /** 18 | * @author steven 19 | * @date 2020/11/11 20 | */ 21 | public class BlockListActivity extends FragmentActivity { 22 | private RecyclerView mRecyclerView; 23 | private MyAdapter mAdapter; 24 | private ArrayList mListData = new ArrayList(); 25 | 26 | @RequiresApi(api = Build.VERSION_CODES.M) 27 | @Override 28 | protected void onCreate(Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_block_list); 31 | mRecyclerView = findViewById(R.id.rv_block_list); 32 | for (int i = 0; i < 100; i++) { 33 | mListData.add(i); 34 | } 35 | mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); 36 | mRecyclerView = findViewById(R.id.rv_block_list); 37 | mAdapter = new MyAdapter(); 38 | mRecyclerView.setAdapter(mAdapter); 39 | 40 | //模拟滑动卡顿的情况 41 | mRecyclerView.setOnScrollChangeListener(new View.OnScrollChangeListener() { 42 | @Override 43 | public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { 44 | if (Math.random() < 0.01) { 45 | try { 46 | Thread.sleep(2600); 47 | } catch (InterruptedException e) { 48 | e.printStackTrace(); 49 | } 50 | } 51 | } 52 | }); 53 | } 54 | 55 | class MyHolder extends RecyclerView.ViewHolder { 56 | TextView textView; 57 | 58 | public MyHolder(@NonNull View itemView) { 59 | super(itemView); 60 | textView = itemView.findViewById(R.id.tv_block_list); 61 | } 62 | 63 | public void setData(int position) { 64 | textView.setText(String.valueOf(mListData.get(position))); 65 | } 66 | } 67 | 68 | class MyAdapter extends RecyclerView.Adapter { 69 | 70 | @NonNull 71 | @Override 72 | public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { 73 | View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_block_scrolling, viewGroup, false); 74 | return new MyHolder(v); 75 | } 76 | 77 | @Override 78 | public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) { 79 | ((MyHolder) viewHolder).setData(i); 80 | } 81 | 82 | @Override 83 | public int getItemCount() { 84 | return mListData.size(); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/apminsightdemo/FirstActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.apminsightdemo; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.DialogInterface; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.support.v4.app.FragmentActivity; 8 | import android.support.v4.app.FragmentTransaction; 9 | import android.view.View; 10 | import android.widget.Toast; 11 | 12 | import com.example.apminsightdemo.fragment.ListFragment; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | 18 | /** 19 | * FirstActivity 20 | * 21 | * @author steven 22 | * @date 2023/11/11 23 | */ 24 | public class FirstActivity extends FragmentActivity { 25 | private ListFragment mFragment; 26 | 27 | @Override 28 | protected void onCreate(Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_main); 31 | initFragment(); 32 | initData(); 33 | } 34 | 35 | 36 | private void initFragment() { 37 | mFragment = new ListFragment(); 38 | FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); 39 | transaction.replace(R.id.text_home, mFragment).commit(); 40 | } 41 | 42 | 43 | private void initData() { 44 | 45 | List lvItemList = new ArrayList<>(); 46 | lvItemList.add(new ListFragment.LvItem("启动APMPlus监控", new ListFragment.OnClick() { 47 | @Override 48 | public void click(View view) { 49 | showDialog(); 50 | } 51 | })); 52 | 53 | mFragment.addAllList(lvItemList); 54 | } 55 | 56 | 57 | 58 | /** 59 | * 模拟用户协议和隐私协议弹窗,用户点击同意后开启监控 60 | */ 61 | private void showDialog() { 62 | AlertDialog alertDialog = new AlertDialog.Builder(FirstActivity.this) 63 | //标题 64 | .setTitle("个人信息保护") 65 | //内容 66 | .setMessage("同意《用户协议》和《隐私政策》后开启监控") 67 | //图标 68 | .setIcon(R.mipmap.ic_launcher) 69 | .setPositiveButton("同意", new DialogInterface.OnClickListener() { 70 | @Override 71 | public void onClick(DialogInterface dialog, int which) { 72 | //开始APM监控,并采集数据,需要在同意隐私合规后调用 73 | App.startMonitor(getApplication()); 74 | startActivity(new Intent(FirstActivity.this,MainActivity.class)); 75 | } 76 | }) 77 | .setNegativeButton("不同意", new DialogInterface.OnClickListener() { 78 | @Override 79 | public void onClick(DialogInterface dialog, int which) { 80 | } 81 | }) 82 | .create(); 83 | alertDialog.show(); 84 | 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/apminsightdemo/HybridTestActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.apminsightdemo; 2 | 3 | import android.app.Activity; 4 | import android.os.Build; 5 | import android.os.Bundle; 6 | import android.webkit.WebChromeClient; 7 | import android.webkit.WebSettings; 8 | import android.webkit.WebView; 9 | 10 | import com.apmplus.hybrid.webview.HybridMonitorManager; 11 | 12 | /** 13 | * @author steven 14 | * @date 2020/11/11 15 | */ 16 | public class HybridTestActivity extends Activity { 17 | private WebView webView; 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_hybrid_main); 23 | webView = findViewById(R.id.web_view_root); 24 | 25 | configWebViewDebugMode(); 26 | 27 | loadUrl(); 28 | 29 | } 30 | 31 | private void configWebViewDebugMode() { 32 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 33 | WebView.setWebContentsDebuggingEnabled(true); 34 | } 35 | WebSettings webSetting = webView.getSettings(); 36 | webSetting.setDomStorageEnabled(true); 37 | 38 | webView.setWebChromeClient(new WebChromeClient(){ 39 | @Override 40 | public void onProgressChanged(WebView view, int newProgress) { 41 | super.onProgressChanged(view, newProgress); 42 | //js加载 43 | HybridMonitorManager.getInstance().onProgressChanged(view,newProgress); 44 | } 45 | }); 46 | } 47 | 48 | 49 | private void loadUrl() { 50 | final String url = "https://www.volcengine.com/product/apmplus"; 51 | //需要配置监控url 52 | HybridMonitorManager.getInstance().onLoadUrl(webView,url); 53 | webView.loadUrl(url); 54 | } 55 | 56 | 57 | @Override 58 | public void onBackPressed() { 59 | if (webView != null && webView.canGoBack()) { 60 | webView.goBack(); 61 | return; 62 | } 63 | super.onBackPressed(); 64 | } 65 | 66 | 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/apminsightdemo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.apminsightdemo; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.os.SystemClock; 6 | import android.support.v4.app.FragmentActivity; 7 | import android.support.v4.app.FragmentTransaction; 8 | import android.view.View; 9 | 10 | import com.apm.insight.log.VLog; 11 | import com.bytedance.apm.insight.ApmInsightAgent; 12 | import com.bytedance.memory.test.OOMMaker; 13 | import com.example.apminsightdemo.fragment.ListFragment; 14 | 15 | import java.io.IOException; 16 | import java.util.ArrayList; 17 | import java.util.HashMap; 18 | import java.util.List; 19 | 20 | import okhttp3.Call; 21 | import okhttp3.Callback; 22 | import okhttp3.OkHttpClient; 23 | import okhttp3.Request; 24 | import okhttp3.Response; 25 | 26 | /** 27 | * MainActivity 28 | * 29 | * @author steven 30 | * @date 2011/11/11 31 | */ 32 | public class MainActivity extends FragmentActivity { 33 | private ListFragment mFragment; 34 | 35 | @Override 36 | protected void onCreate(Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | setContentView(R.layout.activity_main); 39 | initFragment(); 40 | initData(); 41 | } 42 | 43 | 44 | private void initFragment() { 45 | mFragment = new ListFragment(); 46 | FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); 47 | transaction.replace(R.id.text_home, mFragment).commit(); 48 | } 49 | 50 | 51 | private void initData() { 52 | for (int i = 0; i < 10000; i++) { 53 | VLog.d("vlog", "vlog:" + i); 54 | } 55 | 56 | List lvItemList = new ArrayList<>(); 57 | lvItemList.add(new ListFragment.LvItem("崩溃模拟", new ListFragment.OnClick() { 58 | @Override 59 | public void click(View view) { 60 | throw new RuntimeException("Monitor Exception"); // 执行就崩, 如果应用启动后8秒内崩溃, 则判定为启动崩溃进行上报 61 | } 62 | })); 63 | lvItemList.add(new ListFragment.LvItem("ANR模拟", new ListFragment.OnClick() { 64 | @Override 65 | public void click(View view) { 66 | SystemClock.sleep(20000); // 任意处主线程执行, 执行后手动在屏幕上频繁滑动数下, 等几秒就会有ANR弹窗、数据上报 67 | } 68 | })); 69 | lvItemList.add(new ListFragment.LvItem("自定义错误模拟", new ListFragment.OnClick() { 70 | @Override 71 | public void click(View view) { 72 | App.mMonitorCrash.reportCustomErr("test err", "type1", new RuntimeException()); 73 | } 74 | })); 75 | lvItemList.add(new ListFragment.LvItem("卡顿模拟", new ListFragment.OnClick() { 76 | @Override 77 | public void click(View view) { 78 | try { 79 | Thread.sleep(2600); 80 | testSeriousBlock(); 81 | } catch (Exception e) { 82 | e.printStackTrace(); 83 | } 84 | } 85 | })); 86 | 87 | lvItemList.add(new ListFragment.LvItem("卡顿页面", new ListFragment.OnClick() { 88 | @Override 89 | public void click(View view) { 90 | startActivity(new Intent(MainActivity.this, BlockListActivity.class)); 91 | } 92 | })); 93 | 94 | lvItemList.add(new ListFragment.LvItem("hybrid网页监控", new ListFragment.OnClick() { 95 | @Override 96 | public void click(View view) { 97 | MainActivity.this.startActivity(new Intent(MainActivity.this, HybridTestActivity.class)); 98 | } 99 | })); 100 | //网络监控支持OkHttp 101 | lvItemList.add(new ListFragment.LvItem("网络监控模拟", new ListFragment.OnClick() { 102 | @Override 103 | public void click(View view) { 104 | try { 105 | executeGetAsnWithLog("http://mock-api.com/Rz3yJMnM.mock/get"); 106 | } catch (IOException e) { 107 | e.printStackTrace(); 108 | } 109 | } 110 | })); 111 | lvItemList.add(new ListFragment.LvItem("网络错误监控模拟", new ListFragment.OnClick() { 112 | @Override 113 | public void click(View view) { 114 | try { 115 | executeGetAsnWithLog("http://aa.bb.com/get"); 116 | } catch (IOException e) { 117 | e.printStackTrace(); 118 | } 119 | } 120 | })); 121 | lvItemList.add(new ListFragment.LvItem("内存OOM模拟", new ListFragment.OnClick() { 122 | @Override 123 | public void click(View view) { 124 | OOMMaker.createOOM(); 125 | } 126 | })); 127 | lvItemList.add(new ListFragment.LvItem("事件上报模拟", new ListFragment.OnClick() { 128 | @Override 129 | public void click(View view) { 130 | HashMap dimension = new HashMap<>(); 131 | //维度值 132 | dimension.put("key1", "value1"); 133 | dimension.put("key2", "value2"); 134 | HashMap metric = new HashMap<>(); 135 | //指标值 136 | metric.put("metric1", (double) 10); 137 | metric.put("metric2", 8.8); 138 | ApmInsightAgent.monitorEvent("event1", dimension, metric); 139 | } 140 | })); 141 | 142 | mFragment.addAllList(lvItemList); 143 | } 144 | 145 | private void testSeriousBlock() { 146 | try { 147 | Thread.sleep(2600); 148 | } catch (Exception e) { 149 | } 150 | } 151 | 152 | 153 | private String executeGetAsnWithLog(String url) throws IOException { 154 | OkHttpClient.Builder builder = new OkHttpClient.Builder(); 155 | OkHttpClient thisClient = builder.build(); 156 | Request request = new Request.Builder() 157 | .url(url) 158 | .build(); 159 | Call call = thisClient.newCall(request); 160 | call.enqueue(new Callback() { 161 | @Override 162 | public void onFailure(Call call, IOException e) { 163 | } 164 | 165 | @Override 166 | public void onResponse(Call call, Response response) throws IOException { 167 | response.close(); 168 | } 169 | }); 170 | return ""; 171 | } 172 | 173 | } 174 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/apminsightdemo/fragment/ListFragment.java: -------------------------------------------------------------------------------- 1 | package com.example.apminsightdemo.fragment; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.NonNull; 6 | import android.support.annotation.Nullable; 7 | import android.support.v4.app.Fragment; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.BaseAdapter; 12 | import android.widget.Button; 13 | import android.widget.LinearLayout; 14 | import android.widget.ListView; 15 | 16 | 17 | import com.example.apminsightdemo.R; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | /** 23 | * demo list fragment 24 | * 25 | * @author steven 26 | * @date 2011/11/11 27 | */ 28 | public class ListFragment extends Fragment { 29 | private ListView mLv; 30 | private List mData; 31 | private LvAdapter mAdapter; 32 | 33 | @Nullable 34 | @Override 35 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, 36 | @Nullable Bundle savedInstanceState) { 37 | mLv = new ListView(getContext()); 38 | mLv.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 39 | LinearLayout.LayoutParams.MATCH_PARENT)); 40 | return mLv; 41 | } 42 | 43 | @Override 44 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 45 | super.onActivityCreated(savedInstanceState); 46 | initData(); 47 | } 48 | 49 | private void initData() { 50 | if (mData == null) { 51 | mData = new ArrayList<>(); 52 | } 53 | mAdapter = new LvAdapter(getContext()); 54 | mLv.setAdapter(mAdapter); 55 | } 56 | 57 | 58 | public void addAllList(List items) { 59 | if (mData == null) { 60 | mData = new ArrayList<>(); 61 | } 62 | mData.addAll(items); 63 | if (mAdapter != null) { 64 | mAdapter.notifyDataSetChanged(); 65 | } 66 | 67 | } 68 | 69 | 70 | public static class LvItem { 71 | public String name; 72 | public OnClick onClick; 73 | 74 | public LvItem(String name, OnClick onClick) { 75 | this.name = name; 76 | this.onClick = onClick; 77 | } 78 | } 79 | 80 | public interface OnClick { 81 | void click(View view); 82 | } 83 | 84 | private class LvAdapter extends BaseAdapter { 85 | 86 | private Context context; 87 | 88 | public LvAdapter(Context context) { 89 | this.context = context; 90 | } 91 | 92 | @Override 93 | public int getCount() { 94 | return mData.size(); 95 | } 96 | 97 | @Override 98 | public Object getItem(int position) { 99 | return mData.get(position); 100 | } 101 | 102 | @Override 103 | public long getItemId(int position) { 104 | return position; 105 | } 106 | 107 | @Override 108 | public View getView(final int position, View convertView, ViewGroup parent) { 109 | LinearLayout linearLayout = new LinearLayout(context); 110 | Button accountButton = new Button(context); 111 | accountButton.setOnClickListener(new View.OnClickListener() { 112 | @Override 113 | public void onClick(View v) { 114 | mData.get(position).onClick.click(v); 115 | } 116 | }); 117 | accountButton.setText(mData.get(position).name); 118 | accountButton.setBackgroundColor(getResources().getColor(R.color.colorPrimary)); 119 | accountButton.setTextColor(getResources().getColor(R.color.white)); 120 | LinearLayout.LayoutParams btParams = new LinearLayout.LayoutParams( 121 | ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); 122 | btParams.topMargin = dip2px(10, context); 123 | btParams.bottomMargin = dip2px(10, context); 124 | linearLayout.addView(accountButton, btParams); 125 | return linearLayout; 126 | } 127 | } 128 | 129 | /** 130 | * 根据手机的分辨率从 dp 的单位 转成为 px(像素) 131 | */ 132 | public static int dip2px(float dpValue, @NonNull Context context) { 133 | final float scale = context.getResources().getDisplayMetrics().density; 134 | return (int) (dpValue * scale + 0.5f); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_block_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_hybrid_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_block_scrolling.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/volcengine/APMPlus_Android/ef90e985081b521912bf597f5598c3a923e19604/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/volcengine/APMPlus_Android/ef90e985081b521912bf597f5598c3a923e19604/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/volcengine/APMPlus_Android/ef90e985081b521912bf597f5598c3a923e19604/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/volcengine/APMPlus_Android/ef90e985081b521912bf597f5598c3a923e19604/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/volcengine/APMPlus_Android/ef90e985081b521912bf597f5598c3a923e19604/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | #FFFFFFFF 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 40dp 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ApmInsightDemo 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/com/example/apminsightdemo/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.example.apminsightdemo; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | 5 | repositories { 6 | google() 7 | jcenter() 8 | maven { 9 | url "https://artifact.bytedance.com/repository/Volcengine/" 10 | } 11 | maven { 12 | url "https://artifact.bytedance.com/repository/byteX/" 13 | } 14 | } 15 | dependencies { 16 | classpath 'com.android.tools.build:gradle:4.2.0' 17 | // classpath 'com.android.tools.build:gradle:3.1.2' 18 | //ApmInsight 插件 19 | classpath "com.volcengine:apm_insight_plugin:1.4.2" 20 | 21 | // NOTE: Do not place your application dependencies here; they belong 22 | // in the individual module build.gradle files 23 | } 24 | } 25 | 26 | allprojects { 27 | repositories { 28 | google() 29 | jcenter() 30 | maven { 31 | url 'https://artifact.bytedance.com/repository/Volcengine/' 32 | } 33 | } 34 | } 35 | 36 | task clean(type: Delete) { 37 | delete rootProject.buildDir 38 | } 39 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | 15 | 16 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/volcengine/APMPlus_Android/ef90e985081b521912bf597f5598c3a923e19604/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name='ApmInsightDemo' 2 | include ':app' 3 | --------------------------------------------------------------------------------