Commit 3b381525 authored by wind.wang's avatar wind.wang

init

parents
node_modules/
android/build
\ No newline at end of file
import { NativeModules } from 'react-native';
const { RNMonitor } = NativeModules;
export const REAL_TIME = RNMonitor.REAL_TIME; //实时上传(任何有网络的情况下)
export const REAL_TIME_WIFI = RNMonitor.REAL_TIME_WIFI; //实时WiFi上传(仅WiFi下实时上传)
// export const WIFI = RNMonitor.WIFI; //WiFi下上传(应用启动时 并且是WiFi环境下 才上传log)
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>react-native-monitor</name>
<comment>Project react-native-monitor created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
</projectDescription>
connection.project.dir=../../../../android
eclipse.preferences.version=1
<?xml version="1.0" encoding="UTF-8"?>
<module external.system.id="GRADLE" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
apply plugin: 'com.android.library'
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion "${rootProject.ext.buildToolsVersion}"
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
ndk {
abiFilters "armeabi-v7a", "x86"
}
}
lintOptions {
warning 'InvalidPackage'
}
useLibrary 'org.apache.http.legacy'
}
dependencies {
implementation "com.facebook.react:react-native:+" // From node_modules
implementation group:'com.google.code.gson', name:'gson', version:'2.5'
implementation 'org.litepal.android:core:1.4.1'
implementation 'com.loopj.android:android-async-http:1.4.8'
}
\ No newline at end of file
#Mon Dec 28 10:00:20 PST 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
## This file is automatically generated by Android Studio.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Thu Mar 02 12:49:02 CST 2017
sdk.dir=/Users/yhrun/workspace/Android/IDE/sdk
This diff is collapsed.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.terminus.monitor">
<!-- 在SDCard中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 往SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
</manifest>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<litepal>
<dbname value="TerminusMonitor" />
<version value="10" />
<list>
<mapping class="io.terminus.monitor.model.DeviceInfo" />
<mapping class="io.terminus.monitor.model.ErrorModel" />
<mapping class="io.terminus.monitor.model.EventModel"/>
<mapping class="io.terminus.monitor.model.PageModel"/>
<mapping class="io.terminus.monitor.model.PerformanceModel"/>
<mapping class="io.terminus.monitor.model.RequestModel"/>
</list>
</litepal>
\ No newline at end of file
package io.terminus.monitor;
import android.text.TextUtils;
import android.util.Log;
import io.terminus.monitor.model.Enum.UploadModel;
/**
* User : yh
* Date : 17/2/21
*/
public class AnalyticsConfig {
private static String appKey = "43ce6feebf3c459286e810600e2cb104";
private static String base_url = "https://analytics.terminus.io/collect";
private static UploadModel uploadModel = UploadModel.WIFI_LIMIT;
private static String DeviceId ; //设备id
private static String userId; //用户id
public static void setAppKey(String appKey){
AnalyticsConfig.appKey = appKey;
}
public static String getAppKey(){
if(TextUtils.isEmpty(appKey)){
Log.e("Config Error","appkey is empty,please check");
}
return appKey;
}
public static void setUploadModel(UploadModel model){
AnalyticsConfig.uploadModel = model;
}
public static UploadModel getUploadModel(){
return AnalyticsConfig.uploadModel;
}
public static void setDeviceId(String deviceId){
AnalyticsConfig.DeviceId = deviceId;
}
public static String getDeviceId(){
return AnalyticsConfig.DeviceId;
}
public static void setBase_url(String url){
AnalyticsConfig.base_url = url;
}
public static String getDomain(){
return AnalyticsConfig.base_url;
}
public static String getUserId(){
return AnalyticsConfig.userId;
}
public static void setUserId(String userId){
AnalyticsConfig.userId = userId;
}
}
package io.terminus.monitor;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import org.litepal.LitePal;
import java.util.HashMap;
import java.util.Map;
import io.terminus.monitor.model.BaseModel;
import io.terminus.monitor.model.DeviceInfo;
import io.terminus.monitor.model.Enum.UploadModel;
import io.terminus.monitor.model.ErrorModel;
import io.terminus.monitor.model.EventModel;
import io.terminus.monitor.model.PageModel;
import io.terminus.monitor.model.RequestModel;
import io.terminus.monitor.model.PerformanceModel;
import io.terminus.monitor.module.LitePalHelper;
import io.terminus.monitor.module.UploadManager;
import io.terminus.monitor.util.DeviceUtil;
import io.terminus.monitor.util.ToolUtil;
/**
* User : yh
* Date : 17/2/21
*/
public class RNMobClickAgent {
private static final String TAG = "TerminusMobClick";
private static RNMobClickAgent agent;
private Map<String,PageModel> pageInfo;
private RNMobClickAgent(){
pageInfo = new HashMap<>();
}
private static Context mContext;
public static RNMobClickAgent getInstance(){
if(agent == null){
agent = new RNMobClickAgent();
}
return agent;
}
public void init(Context mContext){
RNMobClickAgent.mContext = mContext;
LitePal.initialize(mContext);
LitePalHelper.getInstance().LogModelRegist(DeviceInfo.class);
LitePalHelper.getInstance().LogModelRegist(ErrorModel.class);
LitePalHelper.getInstance().LogModelRegist(EventModel.class);
LitePalHelper.getInstance().LogModelRegist(PageModel.class);
LitePalHelper.getInstance().LogModelRegist(PerformanceModel.class);
LitePalHelper.getInstance().LogModelRegist(RequestModel.class);
UploadManager.getInstance().init(mContext);
AnalyticsConfig.setDeviceId(DeviceUtil.getDeviceId(mContext));
}
public void setAppKey(String appkey){
//// TODO: 17/2/21
AnalyticsConfig.setAppKey(appkey);
UploadManager.getInstance().addDeviceTask(DeviceUtil.getDeviceInfo(RNMobClickAgent.mContext));
}
public void setChannel(String channel){
//// TODO: 17/2/21
}
public void onEvent(BaseModel event){
UploadManager.getInstance().addTask(modleAppendInfo(event));
}
public void setUploadModel(UploadModel model){
AnalyticsConfig.setUploadModel(model);
}
public void setSignin(String userId){
AnalyticsConfig.setUserId(userId);
}
private BaseModel modleAppendInfo(BaseModel model){
if(!TextUtils.isEmpty(AnalyticsConfig.getUserId())){
model.setUid(AnalyticsConfig.getUserId());
}
model.setDate(ToolUtil.getNowTime());
return model;
}
public void onPageStart(String pageName,String lastPage){
if(TextUtils.isEmpty(pageName)){
Log.e(TAG,"pageName is empty");
return;
}
PageModel model = new PageModel();
model.setDt(pageName);
model.setDr(lastPage);
model.setSt(ToolUtil.getNowTimeMillis());
pageInfo.put(pageName,model);
}
public void onPageEnd(String pageName){
if(!pageInfo.containsKey(pageName) ){
Log.e(TAG,pageName+" not exit");
return;
}
PageModel model = pageInfo.get(pageName);
model.setTp(String.valueOf((ToolUtil.getNowTimeMillis() - model.getSt())/1000));
onEvent(model);
pageInfo.remove(pageName);
}
public Context getContext(){
return mContext;
}
}
package io.terminus.monitor;
import android.support.annotation.UiThread;
import android.view.Choreographer;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableNativeMap;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.modules.debug.FpsDebugFrameCallback;
import com.facebook.react.modules.core.ChoreographerCompat;
import com.google.gson.Gson;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import io.terminus.monitor.model.Enum.UploadModel;
import io.terminus.monitor.model.ErrorModel;
import io.terminus.monitor.model.EventModel;
import io.terminus.monitor.model.PageModel;
import io.terminus.monitor.module.CrashHandler;
import io.terminus.monitor.module.PerFormanceTool;
import io.terminus.monitor.util.ToolUtil;
import io.terminus.monitor.model.RequestModel;
public class RNMonitorModule extends ReactContextBaseJavaModule implements LifecycleEventListener{
private final ReactApplicationContext reactContext;
private FpsDebugFrameCallback callback;
private Timer timer ;
private static final String WIFI_LIMIT = "WIFI_LIMIT";
private static final String REAL_TIME_WIFI = "REAL_TIME_WIFI";
private static final String REAL_TIME = "REAL_TIME";
public RNMonitorModule(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
RNMobClickAgent.getInstance().init(reactContext.getApplicationContext());
PerFormanceTool.getInstance().init(reactContext);
}
@ReactMethod
public void init(String appkey, int model) {
RNMobClickAgent.getInstance().setAppKey(appkey);
UploadModel uModel = UploadModel.getModel(model);
RNMobClickAgent.getInstance().setUploadModel(uModel);
UiThreadUtil.runOnUiThread(new Runnable() {
@Override
public void run() {
if (callback == null) {
callback = new FpsDebugFrameCallback(reactContext);
callback.start();
}
}
});
if(timer != null){
return;
}
// timer = new Timer();
// timer.schedule(new TimerTask() {
// @Override
// public void run() {
// UiThreadUtil.runOnUiThread(new Runnable() {
// @Override
// public void run() {
// if (callback != null) {
// PerFormanceTool.getInstance().setFPSsetFPS(callback.getFPS(), callback.getJSFPS());
// }
// }
// });
// }
// }, 3000, 3000);
reactContext.addLifecycleEventListener(this);
}
@ReactMethod
public Map<String, Object> getConstants() {
final Map<String, Object> constants = new HashMap<>();
constants.put(REAL_TIME, UploadModel.REAL_TIME.model);
constants.put(WIFI_LIMIT, UploadModel.WIFI_LIMIT.model);
constants.put(REAL_TIME_WIFI,UploadModel.REAL_TIME_WIFI.model);
return constants;
}
@ReactMethod
public void onSignIn(String userId) {
RNMobClickAgent.getInstance().setSignin(userId);
}
@ReactMethod
public void onCusEvent(ReadableMap map) {
ReadableNativeMap nativeMap = (ReadableNativeMap) map;
String event_str = new Gson().toJson(nativeMap.toHashMap());
EventModel eventModel = new Gson().fromJson(event_str, EventModel.class);
RNMobClickAgent.getInstance().onEvent(eventModel);
}
@ReactMethod
public void sendRequest(ReadableMap map) {
ReadableNativeMap nativeMap = (ReadableNativeMap) map;
String event_str = new Gson().toJson(nativeMap.toHashMap());
RequestModel requestModel = new Gson().fromJson(event_str, RequestModel.class);
RNMobClickAgent.getInstance().onEvent(requestModel);
}
@ReactMethod
public void onError(ReadableMap map) {
ReadableNativeMap nativeMap = (ReadableNativeMap) map;
String event_str = new Gson().toJson(nativeMap.toHashMap());
ErrorModel errorModel = new Gson().fromJson(event_str, ErrorModel.class);
RNMobClickAgent.getInstance().onEvent(errorModel);
}
@ReactMethod
public void onPageStart(String pageName,String lastPage) {
RNMobClickAgent.getInstance().onPageStart(pageName,lastPage);
}
@ReactMethod
public void onPageEnd(String pageName) {
RNMobClickAgent.getInstance().onPageEnd(pageName);
}
@ReactMethod
public void pageLoadTime(String pageName,String pageTime) {
PerFormanceTool.getInstance().pageLoadTime(pageName,pageTime);
}
@Override
public String getName() {
return "RNMonitor";
}
@Override
public void onHostResume() {
}
@Override
public void onHostPause() {
}
@Override
public void onHostDestroy() {
if(timer != null ){
timer.cancel();
timer = null;
}
}
}
\ No newline at end of file
package io.terminus.monitor;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import com.facebook.react.bridge.JavaScriptModule;
public class RNMonitorPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Arrays.<NativeModule>asList(new RNMonitorModule(reactContext));
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
\ No newline at end of file
package io.terminus.monitor.model;
import com.google.gson.Gson;
import com.loopj.android.http.RequestParams;
import org.litepal.crud.DataSupport;
import java.lang.reflect.Method;
/**
* User : yh
* Date : 17/2/22
*/
public class BaseModel extends DataSupport{
public String toString(){
return new Gson().toJson(this);
}
public long getId(){
return getBaseObjId();
}
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getNs() { return ns; }
public void setNs(String ns) {
this.ns = ns;
}
public String getAv() { return av; }
public void setAv(String av) {
this.av = av;
}
public String getVid() { return vid; }
public void setVid(String vid) {
this.vid = vid;
}
public String getAk() { return ak; }
public void setAk(String ak) {
this.ak = ak;
}
public String getDp() { return dp; }
public void setDp(String dp) {
this.dp = dp;
}
public String getDh() { return dh; }
public void setDh(String dh) {
this.dh = dh;
}
public String getCid() { return cid; }
public void setCid(String cid) {
this.cid = cid;
}
public String getGps() { return gps; }
public void setGps(String gps) {
this.gps = gps;
}
public String getExtra() { return extra; }
public void setExtra(String extra) {
this.extra = extra;
}
public String getMd() {
return md;
}
public void setMd(String md) {
this.md = md;
}
public String getOsn() {
return osn;
}
public void setOsn(String osName) {
this.osn = osn;
}
public String getOsv() {
return osv;
}
public void setOsv(String osv) {
this.osv = osv;
}
public String getBr() {
return br;
}
public void setBr(String br) {
this.br = br;
}
public String getUa() {
return ua;
}
public void setUa(String ua) {
this.ua = ua;
}
private String uid; //登录用户id
private String date; //时间
private String ns; //网络状态
private String av; //应用版本
private String ak; //应用id
private String vid; //访问id
private String dp; //界面名称
private String dh; //应用名
private String cid; //客户端表示,uuid
private String gps; //定位信息
private String ua; //ua信息
private String extra; //扩展
//设备品牌
private String br;
//设备型号
private String md;
// 系统名称
private String osn;
//系统版本
private String osv;
}
package io.terminus.monitor.model;
import org.litepal.crud.DataSupport;
/**
* User : yh
* Date : 17/2/20
*/
public class DeviceInfo extends BaseModel{
public String getSr() {
return sr;
}
public void setSr(String sr) {
this.sr = sr;
}
public String getCh() {
return ch;
}
public void setCh(String ch) {
this.ch = ch;
}
public int getJb() {
return jb;
}
public void setJb(int jb) {
this.jb= jb;
}
public String getRom() {
return rom;
}
public void setRom(String rom) {
this.rom = rom;
}
public String getMem() { return mem; }
public void setMem(String mem) {
this.mem = mem;
}
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public String getSdk() {
return sdk;
}
public void setSdk(String sdk) {
this.sdk = sdk;
}
public String getSd() {
return sd;
}
public void setSd(String sd) {
this.sd = sd;
}
public String getT() {
return t;
}
public void setT(String t) {
this.t = t;
}
//分辨率
private String sr;
//渠道
private String ch;
// 是否越狱
private int jb;
//磁盘大小
private String rom;
//内存
private String mem;
//cpu
private String cpu;
//sd 卡
private String sd;
//sdk信息
private String sdk;
private String t = "device";
}
package io.terminus.monitor.model.Enum;
/**
* User : yh
* Date : 17/2/21
*/
public enum NetInfoEnum {
WIFI("Wifi"),UNKNOWN("unknown"),G3("3G"),G4("4G"),OFFLINE("offline"),G2("2G");
private String status;
NetInfoEnum(String status){
this.status = status;
}
public String getStatus(){
return status;
}
}
package io.terminus.monitor.model.Enum;
/**
* User : yh
* Date : 17/2/22
*/
public enum UploadModel {
WIFI_LIMIT(0),REAL_TIME(1),REAL_TIME_WIFI(2);;
public int model;
UploadModel(int model){
this.model = model;
}
public static UploadModel getModel(int value) {
for(UploadModel model : UploadModel.values()){
if(model.model == value){
return model;
}
}
return WIFI_LIMIT;
}
}
package io.terminus.monitor.model;
import org.litepal.crud.DataSupport;
/**
* User : yh
* Date : 17/2/21
*/
public class ErrorModel extends BaseModel{
public String getErm() {
return erm;
}
public void setErm(String erm) {
this.erm = erm;
}
public String getSta() {
return sta;
}
public void setSta(String sta) {
this.sta = sta;
}
public String getT() {
return t;
}
public void setT(String t) {
this.t = t;
}
private String erm; // 错误信息
private String sta; // 堆栈信息
private String t = "error";
}
package io.terminus.monitor.model;
import org.litepal.crud.DataSupport;
/**
* User : yh
* Date : 17/2/21
*/
public class EventModel extends BaseModel{
private String eventName;
public String getXp() {
return xp;
}
public void setXp(String xp) {
this.xp = xp;
}
public String getX() {
return x;
}
public void setY(String y) {
this.y = y;
}
public String getEventName() {
return eventName;
}
public void setEventName(String eventName) {
this.eventName = eventName;
}
public String getT() {
return t;
}
public void setT(String t) {
this.t = t;
}
private String xp;
private String x;
private String y;
private String t = "event";
}
package io.terminus.monitor.model;
/**
* User : yh
* Date : 17/2/21
*/
public class PageModel extends BaseModel{
public String getDt() {
return dt;
}
public void setDt(String dt) {
this.dt = dt;
}
public String getTp() {
return tp;
}
public void setTp(String tp) {
this.tp = tp;
}
public long getSt() {
return st;
}
public void setSt(long st) {
this.st = st;
}
public String getT() {
return t;
}
public void setT(String t) {
this.t = t;
}
public String getDr() {
return dr;
}
public void setDr(String dr) {
this.dr = dr;
}
private String dt; // 界面标题
private long st; //记录页面开始时间
private String tp; // 页面停留时间
private String dr; // 上一个页面信息
private String t = "document";
}
package io.terminus.monitor.model;
/**
* User : yh
* Date : 17/2/28
*/
public class PerformanceModel extends BaseModel{
// public double getFps() {
// return fps;
// }
//
// public void setFps(double fps) {
// this.fps = fps;
// }
//
// public double getCpu() {
// return cpu;
// }
//
// public void setCpu(double cpu) {
// this.cpu = cpu;
// }
//
// public double getMem() {
// return mem;
// }
//
// public void setMem(double mem) {
// this.mem = mem;
// }
//
// public double getHang() {
// return hang;
// }
//
// public void setHang(double hang) {
// this.hang = hang;
// }
//
// public double getNetflow() {
// return netflow;
// }
//
// public void setNetflow(double netflow) {
// this.netflow = netflow;
// }
public String getNt() {
return nt;
}
public void setNt(String nt) {
this.nt = nt;
}
public String getT() {
return t;
}
public void setT(String t) {
this.t = t;
}
// private double fps;
// private double cpu;
// private double mem;
// private double hang; //延迟
// private double netflow;
private String nt;
private String t = "timing";
}
package io.terminus.monitor.model;
/**
* Created by ZYWu on 2017/7/4.
*/
/**
* User : ZYWu
* Date : 2017/7/4
*/
public class RequestModel extends BaseModel{
public String getTt() {
return tt;
}
public void setTt(String tt) {
this.tt = tt;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getSt() {
return st;
}
public void setSt(String st) {
this.st = st;
}
public String getMe() {
return me;
}
public void setMe(String me) {
this.me = me;
}
public String getReq() {
return req;
}
public void setReq(String req) {
this.req = req;
}
public String getRes() {
return res;
}
public void setRes(String res) {
this.res = res;
}
public String getT() {
return t;
}
public void setT(String t) {
this.t = t;
}
private String tt; // 响应时间
private String url; // 请求路径
private String st; // 响应状态
private String me; // 请求方法
private String req; // 请求体大小
private String res; // 响应体大小
private String t = "request";
}
package io.terminus.monitor.module;
/**
* User : yh
* Date : 17/2/20
*/
import android.content.Context;
import android.widget.Toast;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import io.terminus.monitor.RNMobClickAgent;
import io.terminus.monitor.model.ErrorModel;
import io.terminus.monitor.util.ToolUtil;
/**
* 异常捕获
*/
public class CrashHandler implements Thread.UncaughtExceptionHandler{
private static CrashHandler mHandler;
private Context mContext;
private Thread.UncaughtExceptionHandler mDefaultHandler;
private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
private CrashHandler(){
}
public static CrashHandler getInstance(){
if(mHandler == null){
mHandler = new CrashHandler();
}
return mHandler;
}
public void init(Context context){
mContext = context;
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if(mDefaultHandler != null) {
handleException(ex);
}
try{
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(1);
}
private void handleException(Throwable ex){
ErrorModel model = new ErrorModel();
// model.setCreateTime(ToolUtil.getNowTime());
model.setErm(ex.getMessage());
// model.setDate(ToolUtil.getNowTime());
model.setSta(getStrackTrace(ex.getStackTrace()));
System.out.println(getStrackTrace(ex.getStackTrace()));
RNMobClickAgent.getInstance().onEvent(model);
}
public static String getStrackTrace(StackTraceElement[] trace){
if(trace == null || trace.length < 1){
return "";
}
StringBuffer buf = new StringBuffer("");
for(int count = 0; count < trace.length; ++count){
buf.append(trace[count].toString());
buf.append("\n");
}
return buf.toString();
}
}
package io.terminus.monitor.module;
import android.content.Context;
import org.litepal.LitePal;
import org.litepal.crud.DataSupport;
import java.util.ArrayList;
import java.util.List;
import io.terminus.monitor.model.BaseModel;
/**
* User : yh
* Date : 17/2/21
*/
public class LitePalHelper<T extends BaseModel> {
private static LitePalHelper helper;
private List<Class<T> > classList;
private LitePalHelper(){
classList = new ArrayList<>();
}
public void init(Context mContext){
LitePal.initialize(mContext);
}
public void LogModelRegist(Class<T> t){
if(classList.contains(t)){
return;
}
classList.add(t);
}
public static LitePalHelper getInstance(){
if(helper == null){
helper = new LitePalHelper();
}
return helper;
}
public void save(T t){
t.save();
}
public T getData(Class<T> t){
return DataSupport.find(t,1);
}
public void deleteData(Class<T> t,long id){
DataSupport.delete(t,id);
}
public List<T> getAllData(){
List<T> all = new ArrayList<>();
for(Class<T> cls : classList){
all.addAll(DataSupport.findAll(cls));
}
return all;
}
public int count(){
int count = 0;
for(Class<T> cls : classList){
count += DataSupport.count(cls);
}
return count;
}
}
package io.terminus.monitor.module;
import android.content.Context;
import android.view.Choreographer;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.modules.debug.FpsDebugFrameCallback;
import io.terminus.monitor.model.PerformanceModel;
import io.terminus.monitor.util.ToolUtil;
/**
* User : yh
* Date : 17/2/22
*/
public class PerFormanceTool {
private static PerFormanceTool tool;
private double fps;
private double jsfps;
private double cpu;
private double memory;
private PerFormanceTool(){
}
public static PerFormanceTool getInstance(){
if(tool == null){
tool = new PerFormanceTool();
}
return tool;
}
public void init(final ReactContext mContext){
// mFrameCallback = new FpsDebugFrameCallback(Choreographer.getInstance(), mContext);
// mFrameCallback.start();
}
public void pageLoadTime(String pageName,String pageTime) {
PerformanceModel model = new PerformanceModel();
model.setNt(pageTime);
model.setDp(pageName);
UploadManager.getInstance().addTask(model);
}
public void setFPS(double fps,double jsfps){
this.fps = fps;
this.jsfps = jsfps;
this.cpu = ToolUtil.getProcessCpuRate();
this.memory = Runtime.getRuntime().totalMemory()/(1024*1024.0);
PerformanceModel model = new PerformanceModel();
// model.setFps(fps);
// model.setCpu(cpu);
// model.setMem( memory);
UploadManager.getInstance().addTask(model);
}
}
package io.terminus.monitor.module;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.text.TextUtils;
import android.widget.Toast;
import com.google.gson.Gson;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;
import com.loopj.android.http.ResponseHandlerInterface;
import com.loopj.android.http.SyncHttpClient;
import com.loopj.android.http.PreemptiveAuthorizationHttpRequestInterceptor;
import java.util.ArrayList;
import io.terminus.monitor.AnalyticsConfig;
import io.terminus.monitor.RNMobClickAgent;
import io.terminus.monitor.model.BaseModel;
import io.terminus.monitor.model.DeviceInfo;
import io.terminus.monitor.model.Enum.NetInfoEnum;
import io.terminus.monitor.model.Enum.UploadModel;
import io.terminus.monitor.util.DeviceIDUtil;
import io.terminus.monitor.util.DeviceUtil;
import io.terminus.monitor.util.ToolUtil;
/**
* User : yh
* Date : 17/2/21
*/
public class UploadManager {
private static UploadManager manager;
private ArrayList<BaseModel> taskQueue;
private TaskThread taskThread;
private ConnectionChangeReceiver receiver;
private NetInfoEnum netState;
private SyncHttpClient netClient;
private final int LIMIT = 20;
private Context cusmcontext;
private UploadManager(){
taskQueue = new ArrayList<BaseModel>();
taskThread = new TaskThread();
taskThread.start();
}
public static UploadManager getInstance(){
if(manager == null){
manager = new UploadManager();
}
return manager;
}
public void init(Context mcontext){
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
receiver = new ConnectionChangeReceiver();
mcontext.registerReceiver(receiver,intentFilter);
netState = DeviceUtil.getNetWorkInfo(mcontext);
netClient = new SyncHttpClient();
netClient.addHeader("User-Agent","Android");
netClient.addHeader("Referer","home_page");
cusmcontext = mcontext;
synchronized (taskQueue) {
taskQueue.addAll(LitePalHelper.getInstance().getAllData());
taskQueue.notifyAll();
}
}
public void LoadLogFromDB(){
synchronized (taskQueue) {
taskQueue.addAll(LitePalHelper.getInstance().getAllData());
if(!taskQueue.isEmpty()){
taskQueue.notifyAll();
}
}
}
public void addTask(BaseModel model){
LitePalHelper.getInstance().save(applyBaseParam(model));
if(AnalyticsConfig.getUploadModel() == UploadModel.REAL_TIME){
synchronized (taskQueue) {
taskQueue.addAll(LitePalHelper.getInstance().getAllData());
taskQueue.notifyAll();
}
}else if((AnalyticsConfig.getUploadModel() == UploadModel.WIFI_LIMIT || AnalyticsConfig.getUploadModel() == UploadModel.REAL_TIME_WIFI)&& netState == NetInfoEnum.WIFI){
synchronized (taskQueue){
if(LitePalHelper.getInstance().count() >= LIMIT){
taskQueue.addAll(LitePalHelper.getInstance().getAllData());
taskQueue.notifyAll();
}
}
}
}
public void addDeviceTask(BaseModel model){
LitePalHelper.getInstance().save(applyBaseParam(model));
synchronized (taskQueue) {
taskQueue.addAll(LitePalHelper.getInstance().getAllData());
taskQueue.notifyAll();
}
}
public BaseModel applyBaseParam(BaseModel model){
model.setDate(ToolUtil.getNowTime());
model.setNs(DeviceUtil.getNetWorkInfo(cusmcontext).getStatus());
model.setAv(DeviceUtil.getAppVersion(cusmcontext));
model.setUid(AnalyticsConfig.getUserId());
model.setAk(AnalyticsConfig.getAppKey());
DeviceIDUtil DeviceID = new DeviceIDUtil(cusmcontext);
model.setVid(DeviceID.getDeviceUUId().toString());
model.setCid(DeviceID.getDeviceId());
model.setDh(cusmcontext.getPackageName());
model.setBr(Build.MODEL);
model.setOsv(Build.VERSION.RELEASE);
model.setMd(Build.MODEL);
String osName = Build.MANUFACTURER + " android";
model.setOsn(osName);
model.setGps(DeviceUtil.locationInfo(cusmcontext));
model.setUa("Android");
return model;
}
private class TaskThread extends Thread{
@Override
public void run() {
while (true){
synchronized (taskQueue){
if(taskQueue.isEmpty()){
try {
taskQueue.wait();
}catch (Exception e){
}
}else{
RequestParams params = new RequestParams();
params.put("ak",AnalyticsConfig.getAppKey());
params.put("cid",AnalyticsConfig.getDeviceId());
params.put("ip",DeviceUtil.getNetIp());
params.put("uid",AnalyticsConfig.getUserId());
for(BaseModel model : taskQueue){
LitePalHelper.getInstance().deleteData(model.getClass(),model.getId());
params.add("data",ToolUtil.toRequestParams(model).toString());
}
taskQueue.clear();
netClient.post(AnalyticsConfig.getDomain(), params, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, org.apache.http.Header[] headers, byte[] responseBody) {
}
@Override
public void onFailure(int statusCode, org.apache.http.Header[] headers, byte[] responseBody, Throwable error) {
}
});
}
}
}
}
}
public class ConnectionChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
netState = DeviceUtil.getNetWorkInfo(context);
// if(netState == NetInfoEnum.WIFI && AnalyticsConfig.getUploadModel() == UploadModel.REAL_TIME){
// LoadLogFromDB();
// }
}
}
}
package io.terminus.monitor.util;
/**
* Created by ZYWu on 2017/6/22.
*/
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import android.content.Context;
import android.content.SharedPreferences;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import java.io.UnsupportedEncodingException;
import java.util.UUID;
public class DeviceIDUtil {
protected static final String PREFS_FILE = "device_id.xml";
protected static final String PREFS_DEVICE_ID = "device_id";
protected static volatile UUID uuid;
public DeviceIDUtil(Context context) {
this.createUUID(context);
}
private void createUUID(Context context) {
if(uuid == null) {
Class var2 = DeviceIDUtil.class;
synchronized(DeviceIDUtil.class) {
if(uuid == null) {
SharedPreferences prefs = context.getSharedPreferences("device_id.xml", 0);
String id = prefs.getString("device_id", (String)null);
if(id != null) {
uuid = UUID.fromString(id);
} else {
String androidId = Settings.Secure.getString(context.getContentResolver(), "android_id");
try {
if(!"9774d56d682e549c".equals(androidId)) {
uuid = UUID.nameUUIDFromBytes(androidId.getBytes("utf8"));
} else {
String e = ((TelephonyManager)context.getSystemService("phone")).getDeviceId();
uuid = e != null?UUID.nameUUIDFromBytes(e.getBytes("utf8")):UUID.randomUUID();
}
} catch (UnsupportedEncodingException var8) {
throw new RuntimeException(var8);
}
prefs.edit().putString("device_id", uuid.toString()).commit();
}
}
}
}
}
public UUID getDeviceUUId() {
return uuid;
}
public String getDeviceId() {
return this.getDeviceUUId().toString();
}
}
This diff is collapsed.
package io.terminus.monitor.util;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.text.format.DateFormat;
import com.google.gson.Gson;
import com.loopj.android.http.RequestParams;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import io.terminus.monitor.AnalyticsConfig;
import io.terminus.monitor.model.Enum.NetInfoEnum;
import java.util.Calendar;
import java.util.Date;
import java.util.Objects;
/**
* User : yh
* Date : 17/2/20
*/
public class ToolUtil {
public static boolean isDebug(Context mContext){
ApplicationInfo info = mContext.getApplicationInfo();
if((info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0){
return true;
}
return false;
}
public static boolean isWifi(Context mContext){
if(DeviceUtil.getNetWorkInfo(mContext) == NetInfoEnum.WIFI){
return true;
}
return false;
}
public static boolean root(){
try{
if(!new File("/system/bin/su").exists() && !new File("/system/xbin/su").exists()){
return false;
}
return true;
}catch (Exception e){
}
return false;
}
/**
*
* @return yyyy-MM-dd HH:mm:ss
*/
public static String getNowTime(){
long time= System.currentTimeMillis();
return String.valueOf(time);
}
/**
*
* @return time
*/
public static long getNowTimeMillis(){
Date time = new Date(System.currentTimeMillis());
return time.getTime();
}
public static float getProcessCpuRate()
{
float totalCpuTime1 = getTotalCpuTime();
float processCpuTime1 = getAppCpuTime();
try
{
Thread.sleep(360);
}
catch (Exception e)
{
}
float totalCpuTime2 = getTotalCpuTime();
float processCpuTime2 = getAppCpuTime();
float cpuRate = 100 * (processCpuTime2 - processCpuTime1)
/ (totalCpuTime2 - totalCpuTime1);
return cpuRate;
}
private static long getTotalCpuTime()
{ // 获取系统总CPU使用时间
String[] cpuInfos = null;
try
{
BufferedReader reader = new BufferedReader(new InputStreamReader(
new FileInputStream("/proc/stat")), 1000);
String load = reader.readLine();
reader.close();
cpuInfos = load.split(" ");
}
catch (IOException ex)
{
ex.printStackTrace();
}
long totalCpu = Long.parseLong(cpuInfos[2])
+ Long.parseLong(cpuInfos[3]) + Long.parseLong(cpuInfos[4])
+ Long.parseLong(cpuInfos[6]) + Long.parseLong(cpuInfos[5])
+ Long.parseLong(cpuInfos[7]) + Long.parseLong(cpuInfos[8]);
return totalCpu;
}
private static long getAppCpuTime()
{ // 获取应用占用的CPU时间
String[] cpuInfos = null;
try
{
int pid = android.os.Process.myPid();
BufferedReader reader = new BufferedReader(new InputStreamReader(
new FileInputStream("/proc/" + pid + "/stat")), 1000);
String load = reader.readLine();
reader.close();
cpuInfos = load.split(" ");
}
catch (IOException ex)
{
ex.printStackTrace();
}
long appCpuTime = Long.parseLong(cpuInfos[13])
+ Long.parseLong(cpuInfos[14]) + Long.parseLong(cpuInfos[15])
+ Long.parseLong(cpuInfos[16]);
return appCpuTime;
}
public static RequestParams toRequestParams(Object obj){
RequestParams params = new RequestParams();
Method[] methods = obj.getClass().getMethods();
try {
for (Method m : methods) {
if (m.getName().startsWith("get") && !m.getName().startsWith("getClass") && !m.getName().equals("getId")) {
if(m.invoke(obj) == null){continue;}
String value = String.valueOf((Object) m.invoke(obj));
value = URLEncoder.encode(value,"UTF-8");
if(value != null){
String name = m.getName().substring(3, 4).toLowerCase() + m.getName().substring(4);
params.put(name,value);
}
}
}
}catch (Exception e){
e.printStackTrace();
}
return params;
}
}
import React from 'react'
import { NativeModules } from 'react-native';
import * as MonitorType from './MonitorType';
const { RNMonitor } = NativeModules;
var Monitor = {
/**
* 统计初始化,
* appkey 系统分配的
* UploadModel 上传方式 ; REAL_TIME : 实时上传 READL_TIME_WIFI :WiFi下实时上传 WIFI : WiFi下首次启动上传
*/
init(appkey,UploadModel){
RNMonitor.init(appkey,UploadModel);
// require('ErrorUtils').setGlobalHandler((error)=>{
// RNMonitor.onError({erm:error.message,sta:error.stack})
// })
// this.getNowFormatDate = this.getNowFormatDate.bind(this);
},
/***
* 用户统计
*/
onSignIn(userId){
RNMonitor.onSignIn(userId);
},
/**
* event 数据结构
* {
* eventPageName 事件所在页面
* eventId, 事件id
* createTime, 事件发生时间 //可不传
* eventName, 事件名称
* extra,
* }
*/
onCusEvent(obj){
if(!obj){
throw new Error("event info should not be null")
return;
}
var keys = ["eventId","eventName","eventPageName","extra","createTime"];
let event = {};
keys.map((key,index)=>{
if(key === 'eventId' && !obj[key]){
throw new Error('eventId should not be null');
return;
}
event[key] = obj[key];
})
if(event.createTime === undefined){
event['createTime'] = this.getNowFormatDate();
}
RNMonitor.onCusEvent(event);
},
/**
* 组件 willmount 方法中调用
* pageObj 为当前页面或组件对象(this),该名称必须与onPageEnd的参数名称保持一致,否则无法正确统计页面停留时间
*/
onPageStart(pageName,lastPage){
// const pageName = pageObj &&
// pageObj._reactInternalInstance &&
// pageObj._reactInternalInstance._currentElement &&
// pageObj._reactInternalInstance._currentElement.type &&
// pageObj._reactInternalInstance._currentElement.type.name
if(pageName){
RNMonitor.onPageStart(pageName,lastPage)
}
},
/**
* pageObj ,或者 页面发生跳转的时候调用
*/
onPageEnd(pageName){
// const pageName = pageObj &&
// pageObj._reactInternalInstance &&
// pageObj._reactInternalInstance._currentElement &&
// pageObj._reactInternalInstance._currentElement.type &&
// pageObj._reactInternalInstance._currentElement.type.name
if(pageName){
RNMonitor.onPageEnd(pageName)
}
},
/**
* pageObj ,或者 页面发生跳转的时候调用
*/
pageLoad(pageName,loadTime){
if(pageName && loadTime ){
RNMonitor.pageLoadTime(pageName,loadTime)
}
},
/* requestParam:中必须包含参数:
*
请求响应时间 tt;
请求路径 url;
响应状态 st;
请求方法 me;
请求体大小 req;
响应体大小 res;
*/
sendRequest(requestParam){
if(requestParam){
RNMonitor.sendRequest(requestParam)
}
},
/* eventParam:中必须包含参数:
*
target xpath xp;
事件坐标x x;
事件坐标y y;
*/
onEvent(eventParam){
if(eventParam){
RNMonitor.event(eventParam)
}
},
/* errorParam:中必须包含参数:
*
错误日志 erm;
堆栈信息 sta;
*/
onError(errorParam){
if(errorParam){
RNMonitor.onError(errorParam)
}
},
getNowFormatDate(){
var date = new Date();
var seperator1 = "/";
var seperator2 = ":";
var month = date.getMonth() + 1;
var strDate = date.getDate();
if (month >= 1 && month <= 9) {
month = "0" + month;
}
if (strDate >= 0 && strDate <= 9) {
strDate = "0" + strDate;
}
var currentdate = date.getFullYear() + seperator1 + month + seperator1 + strDate
+ " " + date.getHours() + seperator2 + date.getMinutes()
+ seperator2 + date.getSeconds();
return currentdate;
}
}
export { Monitor,MonitorType};
#import "RCTBridgeModule.h"
@interface RNMonitor : NSObject <RCTBridgeModule>
@end
#import "RNMonitor.h"
#import "RNMonitorConfig.h"
#import "RNCusEventManager.h"
#import "RNPageManager.h"
#import "RNRequestManager.h"
#import "RNPerformanceManager.h"
#import "RNEventManager.h"
#import "RNLogManager.h"
@implementation RNMonitor
- (NSDictionary *)constantsToExport
{
return @{ @"REAL_TIME": @"1", @"REAL_TIME_WIFI": @"2",@"WIFI":@"3"};
}
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
RCT_EXPORT_MODULE(RNMonitor)
RCT_EXPORT_METHOD(init:(NSString*)appkey model:(NSString*)uploadModel){
NSInteger type = uploadModel.integerValue;
[[RNMonitorConfig shareInstance] startMonitorWithAppKey:appkey];
switch (type) {
case 1:
[[RNMonitorConfig shareInstance] setType:RNUploadTypeRealTime];
break;
case 2:
[[RNMonitorConfig shareInstance] setType:RNUploadTypeWifiLimit];
break;
case 3:
[[RNMonitorConfig shareInstance] setType:RNUploadTypeActivate];
break;
default:
break;
}
}
RCT_EXPORT_METHOD(onSignIn:(NSString*)uid){
[[RNMonitorConfig shareInstance] setUid:uid];
}
RCT_EXPORT_METHOD(onCusEvent:(NSDictionary*)event){
NSArray*keys = @[@"eventId",@"eventName",@"eventPageName",@"extra"];
NSMutableArray *values = [NSMutableArray arrayWithCapacity:4];
for (NSString *key in keys) {
[event.allKeys containsObject:key]?[values addObject:event[key]]: [values addObject:@""];
}
[[RNCusEventManager shareInstance] event:values[0]
eventName:values[1]
pageName:values[2]
extra:values[3]];
}
RCT_EXPORT_METHOD(onPageStart:(NSString*)pageName lastPage:(NSString*)lastPage){
[[RNPageManager shareInstance] startPageView:pageName lastPage:lastPage];
}
RCT_EXPORT_METHOD(onPageEnd:(NSString*)pageName){
[[RNPageManager shareInstance] endPageView:pageName];
}
RCT_EXPORT_METHOD(pageLoadTime:(NSString*)pageName pageTime:(NSString*)time){
[[RNPerformanceManager shareInstance] pageLoadTime:pageName
time:time];
}
/* requestParam:中必须包含参数:
*
请求响应时间 tt;
请求路径 url;
响应状态 st;
请求方法 me;
请求体大小 req;
响应体大小 res;
*/
RCT_EXPORT_METHOD(sendRequest:(NSDictionary*)requestParam){
[[RNRequestManager shareInstance] sendRequest:requestParam];
}
/* eventParam:中必须包含参数:
*
target xpath xp;
事件坐标x x;
事件坐标y y;
*/
RCT_EXPORT_METHOD(event:(NSDictionary*)eventParam){
[[RNEventManager shareInstance] event:eventParam];
}
/* errorParam:中必须包含参数:
*
错误日志 erm;
堆栈信息 sta;
*/
RCT_EXPORT_METHOD(onError:(NSDictionary*)errorParam){
[[RNLogManager shareInstance] handerReactNativeError:errorParam];
}
@end
//
// RNMonitorConfig.h
// RNMonitor
//
// Created by zhiyu on 17/2/23.
// Copyright © 2017年 Facebook. All rights reserved.
//
#import <Foundation/Foundation.h>
extern NSString *KModelName;
extern NSString *KDeviceEntityName;
extern NSString *KEventEntityName;
extern NSString *KPageEntityName;
extern NSString *KLogEntityName;
extern NSString *KPerformanceEntityName;
extern NSString *KRequestEntityName;
typedef NS_ENUM(NSInteger, RNUploadType) {
RNUploadTypeWifiLimit = 1, //wifi+limit
RNUploadTypeActivate, // 启动
RNUploadTypeRealTime // 实时
};
@interface RNMonitorConfig : NSObject
@property(nonatomic,assign)RNUploadType type;
@property(nonatomic,copy)NSString*baseURL;
@property(nonatomic,copy)NSString*appKey;
@property(nonatomic,assign)NSInteger uploadLimit;
@property(nonatomic,copy)NSString* uid;
@property(nonatomic,assign)BOOL Debug;
+ (instancetype)shareInstance;
- (void)startMonitorWithAppKey:(NSString*)appKey ;
@end
//
// RNMonitorConfig.m
// RNMonitor
//
// Created by zhiyu on 17/2/23.
// Copyright © 2017年 Facebook. All rights reserved.
//
#import "RNMonitorConfig.h"
#import "RNPageManager.h"
#import "RNCusEventManager.h"
#import "RNDeviceManager.h"
#import "RNLogManager.h"
#import "RNPerformanceManager.h"
#import "RNRequestManager.h"
#import "RNDevice.h"
#import "Reachability.h"
#import "RNFMDB.h"
#import "RNMonitorUploadManager.h"
NSString * KModelName = @"RNMonitor";
NSString * KDeviceEntityName = @"device";
NSString * KEventEntityName = @"event";
NSString * KPageEntityName = @"document";
NSString * KLogEntityName = @"error";
NSString * KPerformanceEntityName = @"timing";
NSString * KRequestEntityName = @"request";
@implementation RNMonitorConfig{
Reachability *_reachability;
}
+ (instancetype)shareInstance {
static RNMonitorConfig *_instance;
static dispatch_once_t once_t;
dispatch_once(&once_t, ^{
if (!_instance) {
_instance = [[self alloc] init];
}
});
return _instance;
}
- (instancetype)init
{
self = [super init];
if (self) {
_type = RNUploadTypeActivate;
_baseURL = @"https://analytics.terminus.io/collect";
_uploadLimit = 10;
_Debug = YES;
// [NSURLProtocol registerClass:[RNFlow class]];
}
return self;
}
- (void)startMonitorWithAppKey:(NSString *)appKey {
_appKey = appKey;
[self startMonitor];
if (_type == RNUploadTypeActivate) {
[self uploadAllLastMessage:NO];
}else if (_type == RNUploadTypeWifiLimit){
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(netWorkStatusChange) name:kReachabilityChangedNotification object:nil];
_reachability = [Reachability reachabilityForInternetConnection];
[_reachability startNotifier];
[self netWorkStatusChange];
}
}
- (void)startMonitor{
[RNFMDB shareDatabase:KModelName];
[[RNDeviceManager shareInstance] start];
[[RNLogManager shareInstance] start];
[[RNPageManager shareInstance] start];
[[RNPerformanceManager shareInstance] start];
[[RNRequestManager shareInstance] start];
// [[RNCusEventManager shareInstance] start];
}
- (void)uploadAllLastMessage:(BOOL)Limit{
[RNMonitorUploadManager uploadMonitor:KDeviceEntityName];
[RNMonitorUploadManager uploadMonitor:KLogEntityName];
[RNMonitorUploadManager uploadMonitor:KPerformanceEntityName];
[RNMonitorUploadManager uploadMonitor:KRequestEntityName];
[RNMonitorUploadManager uploadMonitor:KPageEntityName];
// [RNMonitorUploadManager uploadMonitor:KEventEntityName];
}
- (void)netWorkStatusChange{
if([_reachability currentReachabilityStatus] == ReachableViaWiFi){
[self uploadAllLastMessage:YES];
}
}
@end
//
// RNMonitorUploadManager.h
// RNMonitor
//
// Created by zhiyu on 17/3/13.
// Copyright © 2017年 Facebook. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RNParamDO;
@interface RNMonitorUploadManager : NSObject
//+ (void)uploadLastMonitor:(BOOL)limit path:(NSString*)path;
//+ (void)upload:(NSArray*)dataArray path:(NSString*)path;
//+ (void)checkUpload:(id)data path:(NSString*)path;
+ (void)uploadMonitor:(NSString *)topic;
+ (void)applyBaseParam:(NSString *)topic
pageName:(NSString*)pageName
data:(RNParamDO*)paramDO;
@end
//
// RNMonitorUploadManager.m
// RNMonitor
//
// Created by zhiyu on 17/3/13.
// Copyright © 2017年 Facebook. All rights reserved.
//
#import "RNMonitorUploadManager.h"
#import "RNDataManager.h"
#import "RNUtil.h"
#import "RNMonitorConfig.h"
#import "RNUpdateService.h"
#import "RNDevice.h"
#import "RNParamDO.h"
#import "RNFMDB.h"
#import "NSObject+RNMIU_ToDictionary.h"
#import "RNLocationManager.h"
@implementation RNMonitorUploadManager
+ (void)uploadMonitor:(NSString *)topic
{
NSArray *array = [[RNFMDB shareDatabase] jq_lookupTable:topic
dicOrModel:[NSDictionary class]
whereFormat:@"where t = '%@'",topic];
if ([RNMonitorConfig shareInstance].uploadLimit && (array.count >= [RNMonitorConfig shareInstance].uploadLimit)) {
NSArray *newArray = [self recombinationArray:array length:[RNMonitorConfig shareInstance].uploadLimit];
[newArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[RNMonitorUploadManager upload:obj table:topic];
}];
}else if(![RNMonitorConfig shareInstance].uploadLimit){
[RNMonitorUploadManager upload:array table:topic];
}
}
+ (void)applyBaseParam:(NSString *)topic
pageName:(NSString*)pageName
data:(RNParamDO*)paramDO {
paramDO.date = [RNUtil getCurrentTime];
paramDO.ns = [RNDevice iphoneNetState];
paramDO.av = [RNDevice appVersion];
paramDO.uid = [RNMonitorConfig shareInstance].uid;
paramDO.ak = [RNMonitorConfig shareInstance].appKey;
paramDO.dp = pageName;
paramDO.dh = [RNDevice bundleId];
paramDO.cid = [RNDevice deviceId];
paramDO.br =@"iphone";
paramDO.md = [RNDevice iphoneType];
paramDO.osn = @"iOS";
paramDO.osv = [RNDevice iphoneSystemVersion];
paramDO.ua = @"IOS";
paramDO.vid = [RNDevice deviceId];
paramDO.t = topic;
if([RNLocationManager shareInstance].location){
paramDO.gps = [RNLocationManager shareInstance] .location;
[RNMonitorUploadManager checkUploadForENV:paramDO table:topic];
}else{
[[RNLocationManager shareInstance] startLocation:^(NSString *location, NSError *error) {
if (location) {
paramDO.gps = location;
}
[RNMonitorUploadManager checkUploadForENV:paramDO table:topic];
}];
}
}
+ (void)checkUploadForENV:(id)data table:(NSString *)tableName{
if ([tableName isEqualToString:KDeviceEntityName]) {
[self upload:@[[data RNMIU_ToDictionary]] table:tableName];
return ;
}
if([RNMonitorConfig shareInstance].Debug){
#if DEBUG
[[RNFMDB shareDatabase] jq_insertTable:tableName dicOrModel:data];
[self upload:@[[data RNMIU_ToDictionary]] table:tableName];
#else
[self checkUpload:data table:tableName];
#endif
}else{
[self checkUpload:data table:tableName];
}
}
+ (void)checkUpload:(id)data table:(NSString *)tableName{
if([RNMonitorConfig shareInstance].type == RNUploadTypeRealTime){
[[RNFMDB shareDatabase] jq_insertTable:tableName dicOrModel:data];
[self upload:@[[data RNMIU_ToDictionary]] table:tableName];
}else if([RNMonitorConfig shareInstance].type == RNUploadTypeWifiLimit ){
[[RNFMDB shareDatabase] jq_insertTable:tableName dicOrModel:data];
![[RNDevice iphoneNetState] isEqualToString:@"wifi"]?: [self uploadMonitor:tableName];
}else if([RNMonitorConfig shareInstance].type == RNUploadTypeActivate){
[[RNFMDB shareDatabase] jq_insertTable:tableName dicOrModel:data];
}
}
// 根据数据上传
+ (void)upload:(id)monData table:(NSString *)tableName{
if (!monData || [(NSArray*)monData count] ==0) {
return;
}
id param =@{@"cid":[RNUtil deviceId],
@"ak":[RNMonitorConfig shareInstance].appKey?:@"",
@"uid":[RNMonitorConfig shareInstance].uid?:@"",
@"data":monData};
[RNUpdateService POST:[RNMonitorConfig shareInstance].baseURL
parameters:param
resultBlock:^(BOOL success, id data, NSError *error) {
if (success) {
[monData enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[[RNFMDB shareDatabase] jq_deleteTable:tableName whereFormat:@"where date = '%@'",obj[@"date"]];
}];
}
}];
}
+ (NSArray *)recombinationArray:(NSArray*)array length:(NSInteger)subSize {
unsigned long count = array.count % subSize == 0 ? (array.count / subSize) : (array.count / subSize + 1);
NSMutableArray *arr = [[NSMutableArray alloc] init];
for (int i = 0; i < count; i ++) {
int index = i * subSize;
NSMutableArray *arr1 = [[NSMutableArray alloc] init];
[arr1 removeAllObjects];
int j = index;
while (j < subSize*(i + 1) && j < array.count) {
[arr1 addObject:[array objectAtIndex:j]];
j += 1;
}
[arr addObject:[arr1 copy]];
}
return [arr copy];
}
@end
//
// LPEventManager.h
// demo
//
// Created by zhiyu on 17/2/22.
// Copyright © 2017年 terminus. All rights reserved.
//
#import <Foundation/Foundation.h>
extern NSString *KReceiveEventNotification;
@interface RNCusEventManager : NSObject
@property(nonatomic,copy) NSString *eventPath;
+ (instancetype)shareInstance;
- (void)start;
- (void)uploadLastEvent:(BOOL)limit;
/**
*eventId 注册的事件ID
*eventName 注册的事件名称
*eventPageName 页面名称
*extra 额外参数
*/
- (void)event:(NSString *)eventId
eventName:(NSString *)eventName
pageName:(NSString *)eventPageName
extra:(NSDictionary*)extra;
@end
//
// LPEventManager.m
// demo
//
// Created by zhiyu on 17/2/22.
// Copyright © 2017年 terminus. All rights reserved.
//
#import "RNCusEventManager.h"
#import "RNMonitorConfig.h"
#import "RNUtil.h"
#import "RNDataManager.h"
#import "RNUpdateService.h"
#import "RNDevice.h"
#import "RNCusEventDO.h"
#import "RNMonitorUploadManager.h"
NSString * KReceiveEventNotification = @"KReceiveEventNotification";
@implementation RNCusEventManager
+ (instancetype)shareInstance {
static RNCusEventManager *_instance;
static dispatch_once_t once_t;
dispatch_once(&once_t, ^{
if (!_instance) {
_instance = [[self alloc] init];
}
});
return _instance;
}
- (void)start{
_eventPath = [RNDataManager creatDataWithFileName:KEventEntityName];
}
- (void)event:(NSString *)eventId
eventName:(NSString *)eventName
pageName:(NSString *)eventPageName
extra:(NSDictionary*)extra {
RNCusEventDO * eventDO = [RNCusEventDO new];
eventDO.epn = eventPageName;
if (eventId) {
eventDO.ei = eventId;
}
if (eventName) {
eventDO.en = eventName;
}
if (extra) {
eventDO.extra = extra;
}
}
@end
//
// RNDeviceManager.h
// RNMonitor
//
// Created by zhiyu on 17/2/22.
// Copyright © 2017年 Facebook. All rights reserved.
//
#import <Foundation/Foundation.h>
typedef void (^RNReadDevices)(BOOL success, NSArray * devices, NSError *error);
@interface RNDeviceManager : NSObject
@property(nonatomic,copy) NSString *devicePath;;
@property(nonatomic,strong) id extra;
+ (instancetype)shareInstance;
- (void)start;
@end
//
// RNDeviceManager.m
// RNMonitor
//
// Created by zhiyu on 17/2/22.
// Copyright © 2017年 Facebook. All rights reserved.
//
#import "RNDeviceManager.h"
#import "RNDevice.h"
#import "RNMonitorConfig.h"
#import "RNDataManager.h"
#import "RNUpdateService.h"
#import "RNUtil.h"
#import "RNDeviceDO.h"
#import "RNFMDB.h"
#import "RNMonitorUploadManager.h"
@interface RNDeviceManager ()
@end
@implementation RNDeviceManager
+ (instancetype)shareInstance {
static RNDeviceManager *_instance;
static dispatch_once_t once_t;
dispatch_once(&once_t, ^{
if (!_instance) {
_instance = [[self alloc] init];
}
});
return _instance;
}
- (instancetype)init
{
self = [super init];
if (self) {
[[RNFMDB shareDatabase] jq_createTable:KDeviceEntityName
dicOrModel:[RNDeviceDO new]];
}
return self;
}
- (void)start{
RNDeviceDO *deviceDO = [RNDeviceDO new];
deviceDO.sr = [RNDevice iphoneResolution];
deviceDO.ch = @"appStore";
deviceDO.jb = [NSString stringWithFormat:@"%d",[RNDevice iphoneIsJailbreak]];
deviceDO.rom = [RNDevice diskOfAllSizeMBytes];
deviceDO.mem = [RNDevice availableMemory];
deviceDO.cpu = [RNDevice cpuType];
deviceDO.sdk = [RNDevice minimumSystemVersion];
if (_extra) {
deviceDO.extra = _extra;
}
[RNMonitorUploadManager applyBaseParam:KDeviceEntityName
pageName:nil
data:deviceDO];
}
@end
//
// LPPageManager.h
// demo
//
// Created by zhiyu on 17/2/22.
// Copyright © 2017年 terminus. All rights reserved.
//
#import <Foundation/Foundation.h>
extern NSString * KEventEntityName;
@interface RNEventManager : NSObject
@property(nonatomic,strong) id extra;
+ (instancetype)shareInstance;
- (void)start;
- (void)event:(NSDictionary *)eventParam;
@end
//
// LPPageManager.m
// demo
//
// Created by zhiyu on 17/2/22.
// Copyright © 2017年 terminus. All rights reserved.
//
#import "RNEventManager.h"
#import "RNMonitorConfig.h"
#import "RNUpdateService.h"
#import "RNFMDB.h"
#import "RNMonitorUploadManager.h"
#import "RNEventDO.h"
@implementation RNEventManager
+ (instancetype)shareInstance {
static RNEventManager *_instance;
static dispatch_once_t once_t;
dispatch_once(&once_t, ^{
if (!_instance) {
_instance = [[self alloc] init];
}
});
return _instance;
}
- (void)start{
[[RNFMDB shareDatabase] jq_createTable:KEventEntityName
dicOrModel:[RNEventDO new]];
}
- (void)event:(NSDictionary *)eventParam
{
RNEventDO *eventDO = [RNEventDO new];
[eventDO setValuesForKeysWithDictionary:eventParam];
if (_extra) {
eventDO.extra = _extra;
}
[RNMonitorUploadManager applyBaseParam:KEventEntityName
pageName:nil
data:eventDO];
}
@end
//
// UncaughtExceptionHandler.h
// iOSCrash
//
// Created by wzy on 16/1/15.
// Copyright © 2016年 wzy. All rights reserved.
//
#import <UIKit/UIKit.h>
extern NSString * KReceiveLogNotification;
@interface RNLogManager : NSObject
@property(nonatomic,copy) NSString *logPath;
+ (instancetype)shareInstance;
- (void)start;
- (void)handerReactNativeError:(NSDictionary *)error;
void HandleException(NSException *exception);
void SignalHandler(int signal);
//开启异常检测机制
void InstallUncaughtExceptionHandler(void);
@end
//
// UncaughtExceptionHandler.m
// iOSCrash
//
// Created by wzy on 16/1/15.
// Copyright © 2016年 wzy. All rights reserved.
//
#import "RNLogManager.h"
#include <libkern/OSAtomic.h>
#include <execinfo.h>
#import "RNMonitorConfig.h"
#import "RNDataManager.h"
#import "RNUtil.h"
#import "RNDevice.h"
#import "RNUpdateService.h"
#import "RNLogDO.h"
#import "NSObject+RNMIU_ToDictionary.h"
#import "RNFMDB.h"
#import "RNMonitorUploadManager.h"
#import "RCTAssert.h"
NSString * KReceiveLogNotification = @"KReceiveLogNotification";
@interface RNLogManager ()<UIAlertViewDelegate>
@end
NSString * const UncaughtExceptionHandlerSignalExceptionName = @"UncaughtExceptionHandlerSignalExceptionName";
NSString * const UncaughtExceptionHandlerSignalKey = @"UncaughtExceptionHandlerSignalKey";
NSString * const UncaughtExceptionHandlerAddressesKey = @"UncaughtExceptionHandlerAddressesKey";
volatile int32_t UncaughtExceptionCount = 0;
const int32_t UncaughtExceptionMaximum = 10;
const NSInteger UncaughtExceptionHandlerSkipAddressCount = 4;
const NSInteger UncaughtExceptionHandlerReportAddressCount = 5;
@implementation RNLogManager{
BOOL dismissed;
}
+ (instancetype)shareInstance {
static RNLogManager *_instance;
static dispatch_once_t once_t;
dispatch_once(&once_t, ^{
if (!_instance) {
_instance = [[self alloc] init];
}
});
return _instance;
}
- (void)start{
[[RNFMDB shareDatabase] jq_createTable:KLogEntityName dicOrModel: [RNLogDO new]];
InstallUncaughtExceptionHandler();
}
+ (NSArray *)backtrace
{
void* callstack[128];
int frames = backtrace(callstack, 128);
char **strs = backtrace_symbols(callstack, frames);
int i;
NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames];
for (
i = UncaughtExceptionHandlerSkipAddressCount;
i < UncaughtExceptionHandlerSkipAddressCount +
UncaughtExceptionHandlerReportAddressCount;
i++)
{
[backtrace addObject:[NSString stringWithUTF8String:strs[i]]];
}
free(strs);
return backtrace;
}
- (void)validateAndSaveCriticalApplicationData
{
}
- (void)handerReactNativeError:(NSDictionary *)error{
RNLogDO *logDO = [RNLogDO new];
[logDO setValuesForKeysWithDictionary:error];
[RNMonitorUploadManager applyBaseParam:KLogEntityName
pageName:nil
data:logDO];
}
- (void)handleException:(NSException *)exception
{
RNLogDO *logDO = [RNLogDO new];
logDO.erm = [exception reason];
logDO.sta = [[exception userInfo] objectForKey:UncaughtExceptionHandlerAddressesKey] ;
[RNMonitorUploadManager applyBaseParam:KLogEntityName
pageName:nil
data:logDO];
}
@end
// 异常处理
void HandleException(NSException *exception)
{
int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);
if (exceptionCount > UncaughtExceptionMaximum)
{
return;
}
NSArray *callStack = [RNLogManager backtrace];
NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:[exception userInfo]];
[userInfo setObject:callStack forKey:UncaughtExceptionHandlerAddressesKey];
[[RNLogManager shareInstance] performSelectorOnMainThread:@selector(handleException:)
withObject:[NSException exceptionWithName:[exception name] reason:[exception reason] userInfo:userInfo]
waitUntilDone:YES];
}
void SignalHandler(int signal)
{
int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);
if (exceptionCount > UncaughtExceptionMaximum)
{
return;
}
NSMutableDictionary *userInfo =[NSMutableDictionary dictionaryWithObject:[NSNumber numberWithInt:signal] forKey:UncaughtExceptionHandlerSignalKey];
NSArray *callStack = [RNLogManager backtrace];
[userInfo setObject:callStack forKey:UncaughtExceptionHandlerAddressesKey];
id exception = [NSException exceptionWithName:UncaughtExceptionHandlerSignalExceptionName
reason:[NSString stringWithFormat:NSLocalizedString(@"Signal %d was raised.", nil),signal]
userInfo:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:signal] forKey:UncaughtExceptionHandlerSignalKey]];
[[RNLogManager shareInstance] performSelectorOnMainThread:@selector(handleException:)
withObject:exception
waitUntilDone:YES];
}
void InstallUncaughtExceptionHandler(void)
{
NSSetUncaughtExceptionHandler(&HandleException);
signal(SIGABRT, SignalHandler);
signal(SIGILL, SignalHandler);
signal(SIGSEGV, SignalHandler);
signal(SIGFPE, SignalHandler);
signal(SIGBUS, SignalHandler);
signal(SIGPIPE, SignalHandler);
}
//
// RNEventDO.h
// Pods
//
// Created by zhiyu on 2017/6/21.
//
//
#import <Foundation/Foundation.h>
#import "RNParamDO.h"
@interface RNCusEventDO : RNParamDO
/** 事件发生的界面*/
@property(nonatomic,copy) NSString *epn;
/** 事件名称*/
@property(nonatomic,copy) NSString *en;
/** 事件id*/
@property(nonatomic,copy) NSString *ei;
@end
//
// RNEventDO.m
// Pods
//
// Created by zhiyu on 2017/6/21.
//
//
#import "RNCusEventDO.h"
@implementation RNCusEventDO
@end
//
// RNDeviceDO.h
// Pods
//
// Created by zhiyu on 2017/6/21.
//
//
#import <Foundation/Foundation.h>
#import "RNParamDO.h"
@interface RNDeviceDO : RNParamDO
/** 渠道 */
@property(nonatomic,copy) NSString *ch;
/** 分辨率 */
@property(nonatomic,copy) NSString *sr;
/** 是否越狱 */
@property(nonatomic,copy) NSString *jb;
/** 磁盘大小 */
@property(nonatomic,copy) NSString *rom;
/** 内存大小 */
@property(nonatomic,copy) NSString *mem;
/** cpu使用 */
@property(nonatomic,copy) NSString *cpu;
/** sdk信息 */
@property(nonatomic,copy) NSString *sdk;
@end
//
// RNDeviceDO.m
// Pods
//
// Created by zhiyu on 2017/6/21.
//
//
#import "RNDeviceDO.h"
@implementation RNDeviceDO
@end
//
// RNEventDO.h
// Pods
//
// Created by zhiyu on 2017/6/29.
//
//
#import "RNParamDO.h"
@interface RNEventDO : RNParamDO
/** 事件坐标x */
@property(nonatomic,copy) NSString *x;
/** 事件坐标y */
@property(nonatomic,copy) NSString *y;
/** xpath */
@property(nonatomic,copy) NSString *xp;
@end
//
// RNEventDO.m
// Pods
//
// Created by zhiyu on 2017/6/29.
//
//
#import "RNEventDO.h"
@implementation RNEventDO
@end
//
// RNLogDO.h
// Pods
//
// Created by zhiyu on 2017/6/21.
//
//
#import <Foundation/Foundation.h>
#import "RNParamDO.h"
@interface RNLogDO : RNParamDO
/** 错误日志*/
@property(nonatomic,copy) NSString *erm;
/** 堆栈信息*/
@property(nonatomic,copy) NSString *sta;
@end
//
// RNLogDO.m
// Pods
//
// Created by zhiyu on 2017/6/21.
//
//
#import "RNLogDO.h"
@implementation RNLogDO
@end
//
// RNPageDO.h
// Pods
//
// Created by zhiyu on 2017/6/21.
//
//
#import <Foundation/Foundation.h>
#import "RNParamDO.h"
@interface RNPageDO : RNParamDO
/** 界面名称 */
@property(nonatomic,copy) NSString *dt;
/** 页面停留时间 */
@property(nonatomic,copy) NSString *tp;
/** 上一个界面的 */
@property(nonatomic,copy) NSString *dr;
@property(nonatomic,copy) NSString* startTime;
@end
//
// RNPageDO.m
// Pods
//
// Created by zhiyu on 2017/6/21.
//
//
#import "RNPageDO.h"
@implementation RNPageDO
@end
//
// RNBaseDO.h
// Pods
//
// Created by zhiyu on 2017/6/21.
//
//
#import <Foundation/Foundation.h>
@interface RNParamDO : NSObject
/** 记录时间 */
@property(nonatomic,copy) NSString *date;
/** 应用id */
@property(nonatomic,copy) NSString *ak;
/** 客户端id(deviceId) */
@property(nonatomic,copy) NSString *cid;
/** 用户id */
@property(nonatomic,copy) NSString *uid;
/** 网络状态 */
@property(nonatomic,copy) NSString *ns;
/** 应用版本 */
@property(nonatomic,copy) NSString *av;
/** 界面名称 */
@property(nonatomic,copy) NSString *dp;
/** appName */
@property(nonatomic,copy) NSString *dh;
/** topic */
@property(nonatomic,copy) NSString *t;
/** gps */
@property(nonatomic,copy) NSString *gps;
/** ip */
@property(nonatomic,copy) NSString *ip;
/** 访问id(deviceId) */
@property(nonatomic,copy) NSString *vid;
/** 设备品牌 */
@property(nonatomic,copy) NSString *br;
/** 设备型号 */
@property(nonatomic,copy) NSString *md;
/** 系统名称 */
@property(nonatomic,copy) NSString *osn;
/** 系统版本 */
@property(nonatomic,copy) NSString *osv;
/** 系统版本 */
@property(nonatomic,copy) NSString *ua;
@property(nonatomic,strong) id extra;
@end
//
// RNBaseDO.m
// Pods
//
// Created by zhiyu on 2017/6/21.
//
//
#import "RNParamDO.h"
@implementation RNParamDO
@end
//
// RNPerformanceDO.h
// Pods
//
// Created by zhiyu on 2017/6/29.
//
//
#import "RNParamDO.h"
@interface RNPerformanceDO : RNParamDO
/** 页面加载时间 */
@property(nonatomic,copy) NSString * nt;
@end
//
// RNPerformanceDO.m
// Pods
//
// Created by zhiyu on 2017/6/29.
//
//
#import "RNPerformanceDO.h"
@implementation RNPerformanceDO
@end
//
// RNRequestDO.h
// Pods
//
// Created by zhiyu on 2017/7/3.
//
//
#import <RNParamDO.h>
@interface RNRequestDO : RNParamDO
/** 请求响应时间 */
@property(nonatomic,copy) NSString * tt;
/** 请求路径 */
@property(nonatomic,copy) NSString * url;
/** 响应状态 */
@property(nonatomic,copy) NSString * st;
/** 请求方法 */
@property(nonatomic,copy) NSString * me;
/** 请求体大小 */
@property(nonatomic,copy) NSString * req;
/** 响应体大小 */
@property(nonatomic,copy) NSString * res;
@end
//
// RNRequestDO.m
// Pods
//
// Created by zhiyu on 2017/7/3.
//
//
#import "RNRequestDO.h"
@implementation RNRequestDO
@end
//
// LPPageManager.h
// demo
//
// Created by zhiyu on 17/2/22.
// Copyright © 2017年 terminus. All rights reserved.
//
#import <Foundation/Foundation.h>
extern NSString * KReceivePageNotification;
typedef void (^RNReadPages)(BOOL success, NSArray * pages, NSError *error);
@interface RNPageManager : NSObject
//@property(nonatomic,copy) NSString *pagePath;
@property(nonatomic,strong) id extra;
+ (instancetype)shareInstance;
- (void)start;
/** 记录某个页面开始的时间.
@param pageName 统计的页面名称.
@param extra 额外参数
*/
- (void)startPageView:(NSString *)pageName lastPage:(NSString*)lastPage;
/** 记录某个页面结束的时间.
@param pageName 统计的页面名称.
*/
- (void)endPageView:(NSString *)pageName;
@end
//
// LPPageManager.m
// demo
//
// Created by zhiyu on 17/2/22.
// Copyright © 2017年 terminus. All rights reserved.
//
#import "RNPageManager.h"
#import "RNMonitorConfig.h"
#import "RNDataManager.h"
#import "RNDevice.h"
#import "RNUtil.h"
#import "RNUpdateService.h"
#import "RNPageDO.h"
#import "NSObject+RNMIU_ToDictionary.h"
#import "RNFMDB.h"
#import "RNMonitorUploadManager.h"
NSString * KReceivePageNotification = @"KReceiveDeviceNotification";
@implementation RNPageManager{
NSMutableArray *_currentPageNames;
NSString *_currentPageName;
NSMutableDictionary *_currentData;
}
+ (instancetype)shareInstance {
static RNPageManager *_instance;
static dispatch_once_t once_t;
dispatch_once(&once_t, ^{
if (!_instance) {
_instance = [[self alloc] init];
}
});
return _instance;
}
- (void)start{
[[RNFMDB shareDatabase] jq_createTable:KPageEntityName dicOrModel:[RNPageDO new]];
_currentData = [NSMutableDictionary dictionary];
}
- (void)startPageView:(NSString *)pageName lastPage:(NSString*)lastPage
{
_currentPageName = pageName;
[_currentPageNames addObject:pageName];
RNPageDO *pageDO = [RNPageDO new];
pageDO.dr = lastPage;
pageDO.startTime = [NSString stringWithFormat:@"%f",CACurrentMediaTime()];
pageDO.dt = pageName;
if (_extra) {
pageDO.extra = _extra;
}
[_currentData setObject:pageDO forKey:pageName];
}
- (void)endPageView:(NSString *)pageName {
if ([_currentData.allKeys containsObject:pageName]) {
RNPageDO *pageDO = _currentData[pageName];
double time =(CACurrentMediaTime() - pageDO.startTime.doubleValue);
pageDO.tp = [NSString stringWithFormat:@"%.0f",time];
[RNMonitorUploadManager applyBaseParam:KPageEntityName
pageName:pageName
data:pageDO];
[_currentData removeObjectForKey:pageName];
_currentPageName = nil;
}
}
@end
//
// RNFPS.h
// RNMonitor
//
// Created by zhiyu on 17/3/7.
// Copyright © 2017年 Facebook. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface RNFPS : NSObject
@property(nonatomic,strong) NSMutableArray* FPSs;
+ (instancetype)shareInstance;
- (void)startFPS;
- (void)stopFPS;
@end
//
// RNFPS.m
// RNMonitor
//
// Created by zhiyu on 17/3/7.
// Copyright © 2017年 Facebook. All rights reserved.
//
#import "RNFPS.h"
@implementation RNFPS{
CADisplayLink *_link;
NSUInteger _count;
NSTimeInterval _lastTime;
}
+ (instancetype)shareInstance {
static RNFPS *_instance;
static dispatch_once_t once_t;
dispatch_once(&once_t, ^{
if (!_instance) {
_instance = [[self alloc] init];
}
});
return _instance;
}
- (void)startFPS {
_link = [CADisplayLink displayLinkWithTarget:self selector:@selector(tick:)];
[_link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
_FPSs = [NSMutableArray array];
}
- (void)tick:(CADisplayLink *)link {
if (_lastTime == 0) {
_lastTime = link.timestamp;
return;
}
_count++;
NSTimeInterval delta = link.timestamp - _lastTime;
if (delta < 1) return;
_lastTime = link.timestamp;
float fps = _count / delta;
_count = 0;
NSLog(@"%f",fps);
[_FPSs addObject:[NSNumber numberWithFloat:fps]];
}
- (void)stopFPS{
[_link invalidate];
_link= nil;
}
- (void)dealloc {
[_link invalidate];
_link= nil;
}
@end
//
// RNNetFlow.h
// RNMonitor
//
// Created by zhiyu on 17/3/17.
// Copyright © 2017年 Facebook. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface RNNetFlow : NSObject
+ (NSDictionary *)getNetFlow;
@end
//
// RNNetFlow.m
// RNMonitor
//
// Created by zhiyu on 17/3/17.
// Copyright © 2017年 Facebook. All rights reserved.
//
#import "RNNetFlow.h"
#include <arpa/inet.h>
#include <net/if.h>
#include <ifaddrs.h>
#include <net/if_dl.h>
@implementation RNNetFlow
static NSString *const DataCounterKeyWWANSent = @"WWANSent";
static NSString *const DataCounterKeyWWANReceived = @"WWANReceived";
static NSString *const DataCounterKeyWiFiSent = @"WiFiSent";
static NSString *const DataCounterKeyWiFiReceived = @"WiFiReceived";
+ (NSDictionary *)getNetFlow
{
struct ifaddrs *addrs;
const struct ifaddrs *cursor;
u_int32_t WiFiSent = 0;
u_int32_t WiFiReceived = 0;
u_int32_t WWANSent = 0;
u_int32_t WWANReceived = 0;
if (getifaddrs(&addrs) == 0)
{
cursor = addrs;
while (cursor != NULL)
{
if (cursor->ifa_addr->sa_family == AF_LINK)
{
#ifdef DEBUG
const struct if_data *ifa_data = (struct if_data *)cursor->ifa_data;
if(ifa_data != NULL)
{
NSLog(@"Interface name %s: sent %tu received %tu",cursor->ifa_name,ifa_data->ifi_obytes,ifa_data->ifi_ibytes);
}
#endif
// name of interfaces:
// en0 is WiFi
// pdp_ip0 is WWAN
NSString *name = [NSString stringWithFormat:@"%s",cursor->ifa_name];
if ([name hasPrefix:@"en"])
{
const struct if_data *ifa_data = (struct if_data *)cursor->ifa_data;
if(ifa_data != NULL)
{
WiFiSent += ifa_data->ifi_obytes;
WiFiReceived += ifa_data->ifi_ibytes;
}
}
if ([name hasPrefix:@"pdp_ip"])
{
const struct if_data *ifa_data = (struct if_data *)cursor->ifa_data;
if(ifa_data != NULL)
{
WWANSent += ifa_data->ifi_obytes;
WWANReceived += ifa_data->ifi_ibytes;
}
}
}
cursor = cursor->ifa_next;
}
freeifaddrs(addrs);
}
NSLog(@"nwifiSend:%.2f MBnwifiReceived:%.2f MBn wwansend:%.2f MBn wwanreceived:%.2f MBn",WiFiSent/1024.0/1024.0,WiFiReceived/1024.0/1024.0,WWANSent/1024.0/1024.0,WWANReceived/1024.0/1024.0);
return @{DataCounterKeyWiFiSent:[NSNumber numberWithUnsignedInt:WiFiSent],
DataCounterKeyWiFiReceived:[NSNumber numberWithUnsignedInt:WiFiReceived],
DataCounterKeyWWANSent:[NSNumber numberWithUnsignedInt:WWANSent],
DataCounterKeyWWANReceived:[NSNumber numberWithUnsignedInt:WWANReceived]};
}
@end
//
// RNNetWorkFlow.h
// RNMonitor
//
// Created by zhiyu on 17/3/8.
// Copyright © 2017年 Facebook. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface RNNetWorkFlow : NSObject
@property (nonatomic, assign) u_int32_t kWiFiSent;
@property (nonatomic, assign) u_int32_t kWiFiReceived;
@property (nonatomic, assign) u_int32_t kWWANSent;
@property (nonatomic, assign) u_int32_t kWWANReceived;
+ (instancetype)shareInstance;
- (uint32_t)currentNetFlow;
- (void)startblock:(void (^)(u_int32_t sendFlow, u_int32_t receivedFlow))block;
- (void)stop;
@end
//
// RNNetWorkFlow.m
// RNMonitor
//
// Created by zhiyu on 17/3/8.
// Copyright © 2017年 Facebook. All rights reserved.
//
#import "RNNetWorkFlow.h"
#include <ifaddrs.h>
#include <net/if.h>
@interface RNNetWorkFlow()
@property (nonatomic, copy) void (^netBlock)(u_int32_t sendFlow, u_int32_t receivedFlow); //每秒获取
@property (assign,nonatomic) uint32_t historySent;
@property (assign,nonatomic) uint32_t historyRecived;
@property (assign,nonatomic) BOOL isFirst;
@property (nonatomic, strong)NSTimer *timer;
@end
@implementation RNNetWorkFlow
+ (instancetype)shareInstance {
static RNNetWorkFlow *_instance;
static dispatch_once_t once_t;
dispatch_once(&once_t, ^{
if (!_instance) {
_instance = [[self alloc] init];
}
});
return _instance;
}
- (instancetype)init {
if ([super init]) {
[self getNetflow];
}
return self;
}
- (void)dealloc {
[self.timer invalidate];
self.timer = nil;
self.netBlock = nil;
}
- (void)startblock:(void (^)(u_int32_t sendFlow, u_int32_t receivedFlow))block {
self.netBlock = block;
self.isFirst = YES;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(getNetflow) userInfo:nil repeats:YES];
}
- (void)stop {
[self.timer invalidate];
self.timer = nil;
}
- (uint32_t)currentNetFlow{
return self.historySent + self.historyRecived;
}
/** 流量消耗状态 **/
- (void)getNetflow {
BOOL success;
struct ifaddrs *addrs;
const struct ifaddrs *cursor;
const struct if_data *networkStatisc;
self.kWiFiSent = 0;
self.kWiFiReceived = 0;
self.kWWANSent = 0;
self.kWWANReceived = 0;
NSString *name = @"";
success = getifaddrs(&addrs) == 0;
if (success)
{
cursor = addrs;
while (cursor != NULL)
{
name=[NSString stringWithFormat:@"%s",cursor->ifa_name];
// names of interfaces: en0 is WiFi ,pdp_ip0 is WWAN
if (cursor->ifa_addr->sa_family == AF_LINK)
{
if ([name hasPrefix:@"en"])
{
networkStatisc = (const struct if_data *) cursor->ifa_data;
self.kWiFiSent+=networkStatisc->ifi_obytes;
self.kWiFiReceived+=networkStatisc->ifi_ibytes;
}
if ([name hasPrefix:@"pdp_ip"])
{
networkStatisc = (const struct if_data *) cursor->ifa_data;
self.kWWANSent+=networkStatisc->ifi_obytes;
self.kWWANReceived+=networkStatisc->ifi_ibytes;
}
}
cursor = cursor->ifa_next;
}
freeifaddrs(addrs);
}
//第一次不统计
if (self.isFirst) {
self.isFirst = NO;
}
else {
uint32_t nowSent = (self.kWiFiSent + self.kWWANSent - self.historySent);
uint32_t nowRecived = (self.kWiFiReceived + self.kWWANReceived - self.historyRecived);
if (self.netBlock) {
self.netBlock(nowSent, nowRecived);
}
}
self.historySent = self.kWiFiSent + self.kWWANSent;
self.historyRecived = self.kWiFiReceived + self.kWWANReceived;
}
@end
//
// RNFlow.h
// RNMonitor
//
// Created by zhiyu on 17/3/9.
// Copyright © 2017年 Facebook. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface RNNetworkFlowProtocol : NSURLProtocol
@property(nonatomic,assign)NSUInteger currentFlow;
@end
//
// RNFlow.m
// RNMonitor
//
// Created by zhiyu on 17/3/9.
// Copyright © 2017年 Facebook. All rights reserved.
//
#import "RNNetworkFlowProtocol.h"
#import "RNPerformanceManager.h"
static NSString * const kLPNetworkProtocolHeaderKey = @"networkProtocol";
@interface RNNetworkFlowProtocol ()<NSURLConnectionDataDelegate>
@property(nonatomic,weak)NSURLConnection *connection;
@end
@implementation RNNetworkFlowProtocol
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
if ([NSURLProtocol propertyForKey:kLPNetworkProtocolHeaderKey inRequest:request] ) {
return NO;
}
if([@[@"http",@"https"] containsObject:request.URL.scheme]){
return YES;
}
return NO;
}
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
return request;
}
+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b {
return [super requestIsCacheEquivalent:a toRequest:b];
}
- (void)startLoading {
NSMutableURLRequest *newRequest = [self.request mutableCopy];
newRequest.allHTTPHeaderFields = self.request.allHTTPHeaderFields;
[NSURLProtocol setProperty:@YES forKey:kLPNetworkProtocolHeaderKey inRequest:self.request];
self.connection = [NSURLConnection connectionWithRequest:self.request delegate:self];
[self.connection start];
}
- (void)stopLoading {
[self.client URLProtocolDidFinishLoading:self];
}
#pragma mark - <NSURLConnectionDataDelegate>
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if(connection.originalRequest){
// [[RNPerformanceManager shareInstance] updateNetworkFlow:connection.originalRequest.HTTPBody.length];
}
[self.client URLProtocolDidFinishLoading:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.client URLProtocol:self didLoadData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[self.client URLProtocol:self didFailWithError:error];
}
@end
//
// LPPerformancemanager.h
// demo
//
// Created by zhiyu on 17/2/22.
// Copyright © 2017年 terminus. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface RNPerformanceManager : NSObject
@property(nonatomic,copy) NSString *performancePath;
+ (instancetype)shareInstance;
- (void)start;
//- (void)updateNetworkFlow:(NSUInteger)flow;
/** 记录某个页面的加载时间.
@param pageName 统计的页面名称.
@param time 页面加载时长
@param extra 额外参数
*/
- (void)pageLoadTime:(NSString*)pageName time:(NSString*)time;
//
//- (void)startPagePerformance:(NSString*)pageName;
//- (void)endPagePerformance:(NSDictionary*)extra;
@end
//
// LPPerformancemanager.m
// demo
//
// Created by zhiyu on 17/2/22.
// Copyright © 2017年 terminus. All rights reserved.
//
#import "RNPerformanceManager.h"
#import "RNDataManager.h"
#import <RNDevice.h>
#import "RNFPS.h"
#import "RNSlack.h"
#import "RNMonitorConfig.h"
#import "RNUtil.h"
#import "RNNetFlow.h"
#import "RNNetworkFlowProtocol.h"
#import "RNPerformanceDO.h"
#import "RNFMDB.h"
#import "RNMonitorUploadManager.h"
@implementation RNPerformanceManager{
NSString *_currentPageName;
NSUInteger *_currentFlow;
}
+ (instancetype)shareInstance {
static RNPerformanceManager *_instance;
static dispatch_once_t once_t;
dispatch_once(&once_t, ^{
if (!_instance) {
_instance = [[self alloc] init];
}
});
return _instance;
}
- (void)start{
[[RNFMDB shareDatabase] jq_createTable:KPerformanceEntityName
dicOrModel:[RNPerformanceDO new]];
// [[RNSlack sharedInstance] startMonitor];
// [self startNetWorkFlowProtocol];
}
- (void)pageLoadTime:(NSString *)pageName time:(NSString *)time
{
RNPerformanceDO* perDO = [RNPerformanceDO new];
perDO.nt = time;
[RNMonitorUploadManager applyBaseParam:KPerformanceEntityName
pageName:pageName
data:perDO];
}
//- (void)startNetWorkFlowProtocol{
// Class networkFlowProtocol = NSClassFromString(@"RNNetworkFlowProtocol");
// [NSURLProtocol registerClass:networkFlowProtocol];
//}
//-(void)updateNetworkFlow:(NSUInteger)flow
//{
// _currentFlow += flow;
//}
//- (void)startPagePerformance:(NSString *)pageName
//{
// [[RNFPS shareInstance] startFPS];
// _currentPageName = pageName;
//}
//
//- (void)endPagePerformance:(NSDictionary *)extra
//{
//// NSDictionary *flew = [RNNetFlow getNetFlow];
// if (_currentPageName) {
// [[RNFPS shareInstance] stopFPS];
// NSNumber *FPS = [[RNFPS shareInstance].FPSs valueForKeyPath:@"@avg.floatValue"];
// unsigned int netWorkFlow = [RNNetFlow getNetFlow];
// NSMutableDictionary *dict = [NSMutableDictionary dictionary];
// [dict setObject:_currentPageName forKey:@"PageName"];
// [dict setObject:[NSString stringWithFormat:@"%f",[RNDevice iphoneCpuUsage]]forKey:@"cpu"];
// [dict setObject:[NSString stringWithFormat:@"%f",[RNDevice iphoneUsedMemory]]forKey:@"mem"];
// [dict setObject:[NSString stringWithFormat:@"%f",FPS.floatValue]forKey:@"fps"];
// [dict setObject:[NSString stringWithFormat:@"%ld",_currentFlow] forKey:@"netflow"];
// [dict setObject:[RNUtil getCurrentTime] forKey:@"date"];
// _currentPageName = nil;
//
// if ([RNMonitorConfig shareInstance].uid) {
// [dict setObject:[RNMonitorConfig shareInstance].uid forKey:@"uid"];
// }
//
// }
//
//}
@end
//
// RNSlack.h
// RNMonitor
//
// Created by zhiyu on 17/3/7.
// Copyright © 2017年 Facebook. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface RNSlack : NSObject
@property(nonatomic,strong) NSMutableArray *backSlack;
+ (instancetype) sharedInstance;
- (void) startMonitor;
- (void) endMonitor;
@end
//
// RNSlack.m
// RNMonitor
//
// Created by zhiyu on 17/3/7.
// Copyright © 2017年 Facebook. All rights reserved.
//
#import "RNSlack.h"
#import <libkern/OSAtomic.h>
#import <execinfo.h>
@interface RNSlack(){
CFRunLoopObserverRef _observer;
dispatch_semaphore_t _semaphore;
CFRunLoopActivity _activity;
NSInteger _countTime;
}
@end
@implementation RNSlack
+ (instancetype) sharedInstance{
static dispatch_once_t once;
static id sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (void) startMonitor{
// [self registerObserver];
}
- (void) endMonitor{
if (!_observer) {
return;
}
CFRunLoopRemoveObserver(CFRunLoopGetMain(), _observer, kCFRunLoopCommonModes);
CFRelease(_observer);
_observer = NULL;
}
static void runLoopObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
{
RNSlack *instrance = [RNSlack sharedInstance];
instrance->_activity = activity;
// 发送信号
dispatch_semaphore_t semaphore = instrance->_semaphore;
dispatch_semaphore_signal(semaphore);
}
- (void)registerObserver
{
CFRunLoopObserverContext context = {0,(__bridge void*)self,NULL,NULL};
_observer = CFRunLoopObserverCreate(kCFAllocatorDefault,
kCFRunLoopAllActivities,
YES,
0,
&runLoopObserverCallBack,
&context);
CFRunLoopAddObserver(CFRunLoopGetMain(), _observer, kCFRunLoopCommonModes);
// 创建信号
_semaphore = dispatch_semaphore_create(0);
// 在子线程监控时长
dispatch_async(dispatch_get_global_queue(0, 0), ^{
while (YES)
{
// 假定连续5次超时50ms认为卡顿(当然也包含了单次超时250ms)
long st = dispatch_semaphore_wait(_semaphore, dispatch_time(DISPATCH_TIME_NOW, 50*NSEC_PER_MSEC));
if (st != 0)
{
if (_activity==kCFRunLoopBeforeSources || _activity==kCFRunLoopAfterWaiting)
{
if (++_countTime < 5)
continue;
[self logStack];
}
}
_countTime = 0;
}
});
}
- (void)logStack{
void* callstack[128];
int frames = backtrace(callstack, 128);
char **strs = backtrace_symbols(callstack, frames);
int i;
_backSlack = [NSMutableArray arrayWithCapacity:frames];
for ( i = 0 ; i < frames ; i++ ){
[_backSlack addObject:[NSString stringWithUTF8String:strs[i]]];
}
free(strs);
}
@end
//
// LPPageManager.h
// demo
//
// Created by zhiyu on 17/2/22.
// Copyright © 2017年 terminus. All rights reserved.
//
#import <Foundation/Foundation.h>
extern NSString * KRequestEntityName;
@interface RNRequestManager : NSObject
@property(nonatomic,strong) id extra;
+ (instancetype)shareInstance;
- (void)start;
- (void)sendRequest:(NSDictionary*)requestParam;
@end
//
// LPPageManager.m
// demo
//
// Created by zhiyu on 17/2/22.
// Copyright © 2017年 terminus. All rights reserved.
//
#import "RNRequestManager.h"
#import "RNMonitorConfig.h"
#import "RNUpdateService.h"
#import "RNRequestDO.h"
#import "RNFMDB.h"
#import "RNMonitorUploadManager.h"
@implementation RNRequestManager
+ (instancetype)shareInstance {
static RNRequestManager *_instance;
static dispatch_once_t once_t;
dispatch_once(&once_t, ^{
if (!_instance) {
_instance = [[self alloc] init];
}
});
return _instance;
}
- (void)start{
[[RNFMDB shareDatabase] jq_createTable:KRequestEntityName
dicOrModel:[RNRequestDO new]];
// Class networkFlowProtocol = NSClassFromString(@"RNNetworkFlowProtocol");
// [NSURLProtocol registerClass:networkFlowProtocol];
}
- (void)sendRequest:(NSDictionary *)requestParam
{
RNRequestDO *requestDO = [RNRequestDO new];
[requestDO setValuesForKeysWithDictionary:requestParam];
if (_extra) {
requestDO.extra = _extra;
}
[RNMonitorUploadManager applyBaseParam:KRequestEntityName
pageName:nil
data:requestDO];
}
@end
//
// JQFMDB.h
//
// Created by Joker on 17/3/7.
// GitHub: https://github.com/gaojunquan/JQFMDB
//
#import <Foundation/Foundation.h>
@interface RNFMDB : NSObject
/**
(主键id,自动创建) 返回最后插入的primary key id
@param tableName 表的名称
*/
- (NSInteger)lastInsertPrimaryKeyId:(NSString *)tableName;
/**
单例方法创建数据库, 如果使用shareDatabase创建,则默认在NSDocumentDirectory下创建JQFMDB.sqlite, 但只要使用这三个方法任意一个创建成功, 之后即可使用三个中任意一个方法获得同一个实例,参数可随意或nil
dbName 数据库的名称 如: @"Users.sqlite", 如果dbName = nil,则默认dbName=@"JQFMDB.sqlite"
dbPath 数据库的路径, 如果dbPath = nil, 则路径默认为NSDocumentDirectory
*/
+ (instancetype)shareDatabase;
+ (instancetype)shareDatabase:(NSString *)dbName;
+ (instancetype)shareDatabase:(NSString *)dbName path:(NSString *)dbPath;
/**
非单例方法创建数据库
@param dbName 数据库的名称 如: @"Users.sqlite"
dbPath 数据库的路径, 如果dbPath = nil, 则路径默认为NSDocumentDirectory
*/
- (instancetype)initWithDBName:(NSString *)dbName;
- (instancetype)initWithDBName:(NSString *)dbName path:(NSString *)dbPath;
/**
创建表 通过传入的model或dictionary(如果是字典注意类型要写对),虽然都可以不过还是推荐以下都用model
@param tableName 表的名称
@param parameters 设置表的字段,可以传model(runtime自动生成字段)或字典(格式:@{@"name":@"TEXT"})
@return 是否创建成功
*/
- (BOOL)jq_createTable:(NSString *)tableName dicOrModel:(id)parameters;
/**
同上,
@param nameArr 不允许model或dic里的属性/key生成表的字段,如:nameArr = @[@"name"],则不允许名为name的属性/key 生成表的字段
*/
- (BOOL)jq_createTable:(NSString *)tableName dicOrModel:(id)parameters excludeName:(NSArray *)nameArr;
/**
增加: 向表中插入数据
@param tableName 表的名称
@param parameters 要插入的数据,可以是model或dictionary(格式:@{@"name":@"小李"})
@return 是否插入成功
*/
- (BOOL)jq_insertTable:(NSString *)tableName dicOrModel:(id)parameters;
/**
删除: 根据条件删除表中数据
@param tableName 表的名称
@param format 条件语句, 如:@"where name = '小李'"
@return 是否删除成功
*/
- (BOOL)jq_deleteTable:(NSString *)tableName whereFormat:(NSString *)format, ...;
/**
更改: 根据条件更改表中数据
@param tableName 表的名称
@param parameters 要更改的数据,可以是model或dictionary(格式:@{@"name":@"张三"})
@param format 条件语句, 如:@"where name = '小李'"
@return 是否更改成功
*/
- (BOOL)jq_updateTable:(NSString *)tableName dicOrModel:(id)parameters whereFormat:(NSString *)format, ...;
/**
查找: 根据条件查找表中数据
@param tableName 表的名称
@param parameters 每条查找结果放入model(可以是[Person class] or @"Person" or Person实例)或dictionary中
@param format 条件语句, 如:@"where name = '小李'",
@return 将结果存入array,数组中的元素的类型为parameters的类型
*/
- (NSArray *)jq_lookupTable:(NSString *)tableName dicOrModel:(id)parameters whereFormat:(NSString *)format, ...;
/**
批量插入或更改
@param dicOrModelArray 要insert/update数据的数组,也可以将model和dictionary混合装入array
@return 返回的数组存储未插入成功的下标,数组中元素类型为NSNumber
*/
- (NSArray *)jq_insertTable:(NSString *)tableName dicOrModelArray:(NSArray *)dicOrModelArray;
// `删除表
- (BOOL)jq_deleteTable:(NSString *)tableName;
// `清空表
- (BOOL)jq_deleteAllDataFromTable:(NSString *)tableName;
// `是否存在表
- (BOOL)jq_isExistTable:(NSString *)tableName;
// `表中共有多少条数据
- (int)jq_tableItemCount:(NSString *)tableName;
// `返回表中的字段名
- (NSArray *)jq_columnNameArray:(NSString *)tableName;
// `关闭数据库
- (void)close;
// `打开数据库 (每次shareDatabase系列操作时已经open,当调用close后若进行db操作需重新open或调用shareDatabase)
- (void)open;
/**
增加新字段, 在建表后还想新增字段,可以在原建表model或新model中新增对应属性,然后传入即可新增该字段,该操作已在事务中执行
@param tableName 表的名称
@param parameters 如果传Model:数据库新增字段为建表时model所没有的属性,如果传dictionary格式为@{@"newname":@"TEXT"}
@param nameArr 不允许生成字段的属性名的数组
@return 是否成功
*/
- (BOOL)jq_alterTable:(NSString *)tableName dicOrModel:(id)parameters excludeName:(NSArray *)nameArr;
- (BOOL)jq_alterTable:(NSString *)tableName dicOrModel:(id)parameters;
// ============================= 线程安全操作 ===============================
/**
将操作语句放入block中即可保证线程安全, 如:
Person *p = [[Person alloc] init];
p.name = @"小李";
[jqdb jq_inDatabase:^{
[jqdb jq_insertTable:@"users" dicOrModel:p];
}];
*/
- (void)jq_inDatabase:(void (^)(void))block;
/**
事务: 将操作语句放入block中可执行回滚操作(*rollback = YES;)
Person *p = [[Person alloc] init];
p.name = @"小李";
for (int i=0,i < 1000,i++) {
[jq jq_inTransaction:^(BOOL *rollback) {
BOOL flag = [jq jq_insertTable:@"users" dicOrModel:p];
if (!flag) {
*rollback = YES; //只要有一次不成功,则进行回滚操作
return;
}
}];
}
*/
- (void)jq_inTransaction:(void(^)(BOOL *rollback))block;
@end
This diff is collapsed.
//
// RNUpdateService.h
// RNMonitor
//
// Created by zhiyu on 17/2/27.
// Copyright © 2017年 Facebook. All rights reserved.
//
#import <Foundation/Foundation.h>
typedef void (^RNHttpResultBlock)(BOOL success, id data, NSError *error);
@interface RNUpdateService : NSObject
+ (void)POST:(NSString *)URLString
parameters:(id)params
resultBlock:(RNHttpResultBlock)resultBlock;
@end
//
// RNUpdateService.m
// RNMonitor
//
// Created by zhiyu on 17/2/27.
// Copyright © 2017年 Facebook. All rights reserved.
//
#import "RNUpdateService.h"
#import "RNJSON.h"
#import "RNUtil.h"
@implementation RNUpdateService
+ (void)POST:(NSString *)URLString
parameters:(id)params
resultBlock:(RNHttpResultBlock)resultBlock {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:URLString]];
[request setHTTPMethod:@"POST"];
[request setTimeoutInterval:20];
[request setValue:@"IOS" forHTTPHeaderField:@"User-Agent"];
[request setHTTPBody:[[self appendParams:params] dataUsingEncoding:NSUTF8StringEncoding]];
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
resultBlock(NO,nil,error);
return ;
}
NSError *error;
id dict = LPJSONDecode(data, &error);
if ([dict isKindOfClass:[NSDictionary class]]) {
if (dict[@"error"]) {
dispatch_async(dispatch_get_main_queue(), ^{
resultBlock(NO, nil, dict[@"error"]);
});
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
resultBlock(YES, dict, nil);
});
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
resultBlock(YES, nil, nil);
});
});
}] resume];
}
+ (NSString*)appendParams:(id)parama{
NSString *resultString = @"";
if ([parama isKindOfClass:[NSDictionary class]]) {
for (NSString *key in parama) {
NSString *simpleString = @"";
if ([parama[key] isKindOfClass:[NSArray class]]) {
simpleString = [self appendParamsWithArray:parama[key]];
resultString = [NSString stringWithFormat:@"%@%@%@",resultString,resultString.length>0?@"&":@"",simpleString];
}else if ([parama[key] isKindOfClass:[NSDictionary class]]){
simpleString = [self appendParamsWithDict:parama[key]];
resultString = [NSString stringWithFormat:@"%@%@%@=%@",resultString,resultString.length>0?@"&":@"",key,simpleString];
}else if([parama[key] isKindOfClass:[NSString class]]){
simpleString = parama[key];
resultString = [NSString stringWithFormat:@"%@%@%@=%@",resultString,resultString.length>0?@"&":@"",key,simpleString];
}
}
}
return resultString ;
}
+ (NSString*)appendParamsWithDict:(NSDictionary*)dict{
NSString *resultString = @"";
for (NSString*key in dict.allKeys) {
resultString = [NSString stringWithFormat:@"%@%@%@=%@",resultString,resultString.length>0?@"&":@"",key,dict[key]];
}
return resultString;
}
+ (NSString*)appendParamsWithArray:(NSArray*)array {
NSMutableArray *dataArray = [NSMutableArray array];
NSString *result = @"";
for (NSDictionary*dict in array) {
NSString * dataString= @"";
for (NSString*key in dict.allKeys) {
if([dict[key] isKindOfClass:[NSString class]]){
dataString = [NSString stringWithFormat:@"%@%@%@=%@",dataString,dataString.length>0?@"&":@"",key,[self decodeString:dict[key]]];
}
}
result = [NSString stringWithFormat:@"%@%@data=%@",result,result.length>0?@"&":@"",[self decodeString:dataString]];
}
return result;
}
+ (NSString*)decodeString:(NSString*)string{
return CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(CFStringRef)string,
NULL,
(CFStringRef)@"!*'();:@&=+$,/?%#[]",
kCFStringEncodingUTF8));
}
@end
This diff is collapsed.
This diff is collapsed.
//
// IPAddressConfig.h
// IP_Test
//
// Created by 夏远全 on 16/12/23.
// Copyright © 2016年 xiayuanquan. All rights reserved.
//
#import <Foundation/Foundation.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <errno.h>
#include <net/if_dl.h>
#include <net/ethernet.h>
#include <ifaddrs.h>
#include <arpa/inet.h>
#define BUFFERSIZE 4000
#define MAXADDRS 32
#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))
@interface IPAddressConfig : NSObject
// extern
extern char *if_names[MAXADDRS];
extern char *ip_names[MAXADDRS];
extern char *hw_addrs[MAXADDRS];
extern unsigned long ip_addrs[MAXADDRS];
// Function prototypes
void InitAddresses();
void FreeAddresses();
void GetIPAddresses();
void GetHWAddresses();
@end
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
//
// Created by Allen Chiang on 16/3/17.
// Copyright (c) 2016 terminus. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSObject (RNMIU_ToDictionary)
- (NSDictionary *)RNMIU_ToDictionary;
- (NSDictionary *)RNMIU_ToDictionaryWithDepth:(NSInteger)depth;
@end
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment