CrashSight鸿蒙相关提交

main
Kyle Liu 2026-05-28 18:12:17 +08:00
parent b82464de8c
commit e04dcfee8e
88 changed files with 9848 additions and 5 deletions

View File

@ -707,6 +707,7 @@ internal class BatchBuild
public CrashSightConfig CrashSight_Android { get; set; }
public CrashSightConfig CrashSight_iOS { get; set; }
public CrashSightConfig CrashSight_Harmony{get; set;}
public TalkingDataConfig TalkingData { get; set; }
public ThinkingDataConfig ThinkingData { get; set; }
}
@ -897,6 +898,23 @@ internal class BatchBuild
Debug.Log("CrashSight配置已保存:" + crashSightData.id + "|" + crashSightData.key);
}
#if UNITY_OPENHARMONY
// 处理CrashSight_Harmony配置
if (config.CrashSight_Harmony != null &&
EditorUserBuildSettings.activeBuildTarget == BuildTarget.OpenHarmony)
{
var crashSightData = new PhxhSDK.Data.CrashSightData
{
id = config.CrashSight_Harmony.Id,
key = config.CrashSight_Harmony.Key
};
var json = JsonUtility.ToJson(crashSightData);
WriteEncryptedJsonResource("CrashSightData", json);
Debug.Log("CrashSight配置已保存:" + crashSightData.id + "|" + crashSightData.key);
}
#endif
if (config.TalkingData != null)
{
var talkingDataInitTool = new TalkingDataInitTool

View File

@ -43,10 +43,10 @@ ConfigURL: "http://yhpxkqgzatnrmbws.kedrgame.com"
AppAccessKey: "0SoE48O9sayjkG8J"
AppKey: "uUi_UI1oMKWo0VOSN1zme17Z70-FlAv3Lcx2mNhoYe4="
# 崩溃监控配置(仅 Android
CrashSight_Android:
id: "669a94ce69" # 崩溃上报的 App ID
key: "d9412717-2416-4270-b8bc-f7a0805f988f" # 崩溃上报的 Key
# 崩溃监控配置(仅鸿蒙
CrashSight_Harmony:
id: "88625404e2" # 崩溃上报的 App ID
key: "bff9d9be-bbd7-4fc1-9176-653281f8ff51" # 崩溃上报的 Key
# TalkingData初始化
TalkingData:

View File

@ -0,0 +1,116 @@
#if SDK_CRASHSIGHT
using System;
using PhxhSDK.Data;
using UnityEngine;
using UnityEngine.Diagnostics;
namespace PhxhSDK
{
public class CrashSightSdkHelper : SdkHelper
{
// 设置上报的目标域名,请根据项目需求进行填写。(必填)
private const string crashServerUrl_Android = "https://android.crashsight.qq.com/pb/async";
// 设置上报所指向的APP ID, 并进行初始化。APPID可以在管理端更多->产品设置->产品信息中找到。
// private const string appId_Android = "669a94ce69";
private const string crashServerUrl_iOS = "https://ios.crashsight.qq.com/pb/sync";
// private const string appId_iOS = "6ff03772f9";
private const string crashServerUrl_Harmony = "harmony.crashsight.qq.com";
public override void EarlyInit()
{
// Debug开关Debug模式下会打印更多便于问题定位的Log.
var enableDebug = false;
#if DEBUG
enableDebug = true;
#endif
CrashSightAgent.ConfigDebugMode(enableDebug);
var uploadUrl = "";
switch (Application.platform)
{
case RuntimePlatform.Android:
uploadUrl = crashServerUrl_Android;
break;
case RuntimePlatform.IPhonePlayer:
uploadUrl = crashServerUrl_iOS;
break;
#if UNITY_OPENHARMONY
case RuntimePlatform.OpenHarmony:
uploadUrl = crashServerUrl_Harmony;
break;
#endif
default:
DebugUtil.LogError("CrashSightSdkHelper" + "Unsupported platform: " + Application.platform);
break;
}
if (!string.IsNullOrEmpty(uploadUrl))
{
CrashSightAgent.ConfigCrashServerUrl(uploadUrl);
}
var appId = "";
if (!EncryptedResourceLoader.TryLoadJson<CrashSightData>("CrashSightData", out var data))
{
DebugUtil.LogError("CrashSightSdkHelper", "CrashSightData resource load failed");
return;
}
appId = data.id;
if (!string.IsNullOrEmpty(appId))
{
CrashSightAgent.InitWithAppId(appId);
DebugUtil.Log("CrashSightSdkHelper", "CrashSight appId: " + appId);
}
else
{
DebugUtil.LogError("CrashSightSdkHelper" + "CrashSight appId is empty");
}
}
public override void Init()
{
}
public override void AfterLoginInit()
{
}
public override void Update()
{
}
public override void Release()
{
}
public void TestCrashJava()
{
CrashSightAgent.TestJavaCrash();
}
public void TestOcCrash()
{
CrashSightAgent.TestOcCrash();
}
public void TestCrashException()
{
throw new Exception("测试模拟异常");
}
public void TestCrash()
{
UnityEngine.Diagnostics.Utils.ForceCrash(ForcedCrashCategory.AccessViolation);
}
public void TestNativeCrash()
{
CrashSightAgent.TestNativeCrash();
}
}
}
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f7558a87675ed9b4d8ddf26c290df6d1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,24 @@
{
"group": "CrashSight",
"libs": [
"libz.dylib",
"libc++.dylib"
],
"frameworks": [
"SystemConfiguration.framework",
"Security.framework",
"JavaScriptCore.framework",
"MetricKit.framework:weak",
"OSLog.framework:weak",
"CFNetwork.framework"
],
"headerpaths": [],
"files": [],
"folders": [],
"excludes": ["^.*.meta$", "^.*.mdown$", "^.*.pdf$"],
"compiler_flags": [],
"linker_flags": [
"-ObjC"
]
}

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This Google Mobile Ads plugin library manifest will get merged with your
application's manifest, adding the necessary activity and permissions
required for displaying ads.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.uqm.gcloud.crashsight">
<uses-sdk android:targetSdkVersion="30" android:minSdkVersion="15"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
</manifest>

View File

@ -0,0 +1,4 @@
# crashsight sdk
-keep public class com.uqm.crashsight.** { *; }
-dontwarn com.uqm.crashsight.core.**
-keep class com.uqm.crashsight.core.** { *; }

View File

@ -0,0 +1,2 @@
target=android-26
android.library=true

View File

@ -0,0 +1,20 @@
import { CrashSightMain} from 'crashsight';
import { GetFromGlobalThis } from 'crashsight/../../src/main/ets/common/GlobalThisUtil'
import { common, Context } from '@kit.AbilityKit';
export function RegisterCrashSightBridge() {
let register: Record<string, Object> = {};
register["CrashSightObj"] = new CrashSightClass();
return register;
}
export class CrashSightClass {
initContext(): number {
let context = GetFromGlobalThis("context") as Context;
CrashSightMain.getInstance().initContextInJS(context);
return 1;
}
}

View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Mobile Utils Plugin
Created by Patryk Stepniewski
Copyright (c) 2014-2019 gameDNA Ltd. All Rights Reserved.
-->
<root xmlns:android="http://schemas.openharmony.com">
<addRequestPermissions>
<insert>
ohos.permission.GET_NETWORK_INFO
ohos.permission.INTERNET
ohos.permission.GET_WIFI_INFO
</insert>
</addRequestPermissions>
<resourceCopies>
<log text="CrashSight prebuildCopies"/>
<log text="prebuildCopies $S(PluginDir)/CrashSight.har"/>
<log text="prebuildCopies $S(BuildDir)/entry/hars/CrashSight.har"/>
<copyFile src="$S(PluginDir)/CrashSight.har" dst="$S(BuildDir)/entry/hars/CrashSight.har"/>
</resourceCopies>
<ProjectOHPackageJsonOverridesAddHarPackageNames>
<insert>
CrashSight
</insert>
</ProjectOHPackageJsonOverridesAddHarPackageNames>
<entryAbilityImportAdditions>
<insert>
import { CrashSightMain } from "CrashSight";
</insert>
</entryAbilityImportAdditions>
<AkiJSBindImportAdditions>
<insert>
import {CrashSightClass} from '../entryability/EntryAbility'
</insert>
</AkiJSBindImportAdditions>
<AkiJSBindMainThreadAdditions>
<insert>
nativeRender.JSBind.bindFunction("CrashSightClass.initContext", CrashSightClass.initContext);
</insert>
</AkiJSBindMainThreadAdditions>
<entryAbilityExternalClassAdditions>
<insert>
export class CrashSightClass {
static initContext() :number{
let context = GlobalContext.loadGlobalThis(GlobalContextConstants.UE_ABILITY_CONTEXT) as Context;
CrashSightMain.getInstance().initContextInJS(context);
return 1;
}
}
</insert>
</entryAbilityExternalClassAdditions>
</root>

View File

@ -0,0 +1,81 @@
fileFormatVersion: 2
guid: bf5ae746b5b544136adfc380164166ce
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
: Any
second:
enabled: 0
settings:
Exclude Android: 1
Exclude Editor: 1
Exclude Linux64: 0
Exclude OSXUniversal: 0
Exclude WebGL: 1
Exclude Win: 1
Exclude Win64: 0
Exclude iOS: 1
- first:
Android: Android
second:
enabled: 0
settings:
CPU: ARMv7
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
CPU: AnyCPU
DefaultValueInitialized: true
OS: AnyOS
- first:
Standalone: Linux64
second:
enabled: 1
settings:
CPU: AnyCPU
- first:
Standalone: OSXUniversal
second:
enabled: 1
settings:
CPU: AnyCPU
- first:
Standalone: Win
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Standalone: Win64
second:
enabled: 1
settings:
CPU: AnyCPU
- first:
iPhone: iOS
second:
enabled: 0
settings:
AddToEmbeddedBinaries: false
CPU: AnyCPU
CompileFlags:
FrameworkDependencies:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,93 @@
fileFormatVersion: 2
guid: dade0c46327444572be5b78f63f416be
folderAsset: yes
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
'': Any
second:
enabled: 0
settings:
Exclude Editor: 1
Exclude Linux: 1
Exclude Linux64: 1
Exclude LinuxUniversal: 1
Exclude OSXUniversal: 1
Exclude Win: 1
Exclude Win64: 1
Exclude iOS: 0
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
CPU: AnyCPU
DefaultValueInitialized: true
OS: AnyOS
- first:
Facebook: Win
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Facebook: Win64
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Standalone: Linux
second:
enabled: 0
settings:
CPU: x86
- first:
Standalone: Linux64
second:
enabled: 0
settings:
CPU: x86_64
- first:
Standalone: OSXUniversal
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Standalone: Win
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Standalone: Win64
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
iPhone: iOS
second:
enabled: 1
settings:
AddToEmbeddedBinaries: true
CompileFlags:
FrameworkDependencies: CoreTelephony;Security;
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,245 @@
//
// CrashSight.h
//
// Version: 4.3.8(1084)
//
// Copyright (c) 2017年
//
#import <Foundation/Foundation.h>
#import "CrashSightConfig.h"
#import "CrashSightLog.h"
#define GCLOUD_VERSION_CRASHSIGHT "GCLOUD_VERSION_CRASHSIGHT_4.3.8.1084.sgprod"
typedef NS_OPTIONS(uint32_t, CSExceptionReprotOption) {
CSExceptionReprotOptionNone = 0,
CSExceptionReprotOptionSystemLog = 1 << 0,
CSExceptionReprotOptionCustomLog = 1 << 1,
CSExceptionReprotOptionKV = 1 << 2,
CSExceptionReprotOptionCallback = 1 << 3,
CSExceptionReprotOptionDumpStack = 1 << 4,
};
@interface CrashSight : NSObject
/**
* CrashSight,使CrashSightConfigs
*
* @param appId CrashSight
*/
+ (void)startWithAppId:(NSString * CS_NULLABLE)appId;
/**
* 使CrashSight
*
* @param appId CrashSight
* @param config CrashSightConfig
*/
+ (void)startWithAppId:(NSString * CS_NULLABLE)appId
config:(CrashSightConfig * CS_NULLABLE)config;
/**
* 使CrashSight
*
* @param appId CrashSight
* @param development
* @param config CrashSightConfig
*/
+ (void)startWithAppId:(NSString * CS_NULLABLE)appId
developmentDevice:(BOOL)development
config:(CrashSightConfig * CS_NULLABLE)config;
/**
*
*
* @param userId
*/
+ (void)setUserIdentifier:(NSString *)userId;
/**
*
*
* @param version
*/
+ (void)updateAppVersion:(NSString *)version;
/**
*
*
* @param value KEY
* @param key VALUE
*/
+ (void)setUserValue:(NSString *)value
forKey:(NSString *)key;
/**
* USER ID
*
* @return USER ID
*/
+ (NSString *)crashSightUserIdentifier;
/**
*
*
* @return
*/
+ (NSDictionary * CS_NULLABLE)allUserValues;
+ (void)setUserSceneTag:(NSString *)userSceneTag isUpload:(bool)upload;
+ (NSString *)currentUserSceneTag;
/**
* ID
*
* @return ID
*/
+ (NSString *)crashSightDeviceId;
/**
* Objective-C
*
* @param exception
*/
+ (void)reportException:(NSException *)exception;
/**
*
*
* @param error
*/
+ (void)reportError:(NSError *)error;
/**
* @brief
*
* @param category (Cocoa=3,CSharp=4,JS=5,Lua=6)
* @param aName
* @param aReason
* @param aStackArray
* @param info
* @param terminate 退
*/
+ (void)reportExceptionWithCategory:(NSUInteger)category
name:(NSString *)aName
reason:(NSString *)aReason
callStack:(NSArray *)aStackArray
extraInfo:(NSDictionary *)info
terminateApp:(BOOL)terminate
dumpDataType:(int) dumpDataType
errorAttachmentPath:(NSString *)errorAttachmentPath;
/**
* @brief
*
* @param category (Cocoa=3,CSharp=4,JS=5,Lua=6)
* @param aName
* @param aReason
* @param aStackArray
* @param info
* @param terminate 退
*/
+ (void)reportExceptionWithCategory:(NSUInteger)category
name:(NSString *)aName
reason:(NSString *)aReason
callStack:(NSArray *)aStackArray
extraInfoJSONString:(NSString *)info
terminateApp:(BOOL)terminate
dumpDataType:(int) dumpDataType
errorAttachmentPath:(NSString *)errorAttachmentPath;
+ (void) reportLogInfo:(NSString *)messageType message:(NSString *)message;
+ (void)reportJankWithName:(NSString *)name message:(NSString *)message stack:(NSArray *)stack extraInfo:(NSDictionary *)extraInfo option:(CSExceptionReprotOption)option attachmentPath:(nullable NSString *)attachmentPath;
/**
* SDK
*
* @return SDK
*/
+ (NSString *)sdkVersion;
/**
* APP
*
* @return SDK
*/
+ (NSString *)appVersion;
/**
* App 退
* SDK 5 退 3 退
*
* @return 退
*/
+ (BOOL)isAppCrashedOnStartUpExceedTheLimit;
/**
* crashSight
*/
+ (void)closeCrashReport;
/**
* CrashSightCrash
*/
+ (void)reregisterCrashHandler;
/**
* URLCrashSight
*/
+ (void)setServerUrl:(NSString *)url;
/**
*
*/
+ (void)setAttachmentPath:(NSString *)path;
+ (int)getCrashThreadId;
+ (NSString *)crashSightSessionId;
+ (BOOL)isLastSessionCrash;
+ (NSString *)getLastSessionUserId;
+ (NSDictionary *)ccConifg;
+ (int)getExceptionType:(NSString *)name;
+ (void)setServerEnv:(NSString *)serverEnv;
+ (void)setEngineInfo:(NSString *)version buildConfig:(NSString *)buildConfig language:(NSString *)language locale:(NSString *)locale;
+ (void)enableDetailedPageTracing:(bool)enable;
+ (void)useSavedUserId:(bool)enable;
+ (void)reportStuckWithThreadIndex:(int)threadIndex
maxChecks:(int)maxChecks
checkInterval:(NSTimeInterval)checkInterval
name:(NSString *)name
message:(NSString *)message
extraInfo:(NSString *)extraInfo
dumpNativeType:(int)dumpNativeType
attachPath:(NSString *)attachPath;
// 必须在lua线程调用 否则捕获lua堆栈时会崩溃
+ (void)setLuaState:(nonnull void*)lua;
+ (void)setLuaFuncGetglobal:(nonnull void *)getglobal getfield:(nonnull void *)getfield pushstring:(nonnull void *)pushstring pushinteger:(nonnull void *)pushinteger pcallk:(nonnull void *)pcallk tolstring:(nonnull void *)tolstring settop:(nonnull void *)settop;
@end

View File

@ -0,0 +1,195 @@
//
// CrashSightConfig.h
// CrashSight
//
// Copyright (c) 2016年
//
#pragma once
#define CS_UNAVAILABLE(x) __attribute__((unavailable(x)))
#if __has_feature(nullability)
#define CS_NONNULL __nonnull
#define CS_NULLABLE __nullable
#define CS_START_NONNULL _Pragma("clang assume_nonnull begin")
#define CS_END_NONNULL _Pragma("clang assume_nonnull end")
#else
#define CS_NONNULL
#define CS_NULLABLE
#define CS_START_NONNULL
#define CS_END_NONNULL
#endif
#import <Foundation/Foundation.h>
#import "CrashSightLog.h"
#define CS_CALLBACK_FLAGS_LUA 0x1
#define CS_CALLBACK_FLAGS_JS (0x1 << 1)
#define CS_CALLBACK_FLAGS_CSHARP (0x1 << 2)
#define CS_CALLBACK_FLAGS_CRASH (0x1 << 4)
#define CS_CALLBACK_FLAGS_CUSTOM (0x1 << 5)
typedef NS_ENUM(NSInteger, CSCallbackType) {
CSCallbackTypeNone = 0,
CSCallbackTypeCrash = 2,
CSCallbackTypeCShap = 3,
CSCallbackTypeJS = 5,
CSCallbackTypeLua = 6,
CSCallbackTypeCustom = 8,
CSCallbackTypeJank = 9,
};
typedef CSCallbackType CSExceptionType;
@protocol CrashSightDelegate <NSObject>
@optional
/**
*
*
* @param exception
*
* @return
*/
- (NSString * CS_NULLABLE)attachmentForException:(NSException * CS_NULLABLE)exception callbackType:(CSCallbackType)callbackType;
/**
* UQM
* @return
*/
- (NSString * CS_NULLABLE)attachmentLogPathForExceptionType:(CSExceptionType)exceptionType;
/**
* UQM
*
*/
- (void)attachmentLogUploadResultForExceptionType:(CSExceptionType)exceptionType result:(int) result;
/**
*
*
* @param tacticInfo
*
* @return app
*/
- (BOOL) h5AlertForTactic:(NSDictionary *)tacticInfo;
@end
@interface CrashSightConfig : NSObject
/**
* SDK Debug,
*/
@property (nonatomic, assign) BOOL debugMode;
/**
*
*/
@property (nonatomic, copy) NSString *channel;
/**
*
*/
@property (nonatomic, copy) NSString *version;
/**
*
*/
@property (nonatomic, copy) NSString *deviceIdentifier;
/**
*
*/
@property (nonatomic) BOOL blockMonitorEnable;
/**
*
*/
@property (nonatomic) NSTimeInterval blockMonitorTimeout;
/**
* App Groups Id (使 CrashSight iOS Extension SDK)
*/
@property (nonatomic, copy) NSString *applicationGroupIdentifier;
/**
*
*/
@property (nonatomic) BOOL symbolicateInProcessEnable;
/**
* @deprecate
*
* 退
*/
@property (nonatomic) BOOL unexpectedTerminatingDetectionEnable;
/**
*
*/
@property (nonatomic) BOOL viewControllerTrackingEnable;
/**
* CrashSight Delegate
*/
@property (nonatomic, assign) id<CrashSightDelegate> delegate;
/**
* CrashSightLogLevelSilent
* CrashSightLogLevelWarnWarnError
*/
@property (nonatomic, assign) CrashSightLogLevel reportLogLevel;
/**
*
* SogouInputIPhone.dylib
*/
@property (nonatomic, copy) NSArray *excludeModuleFilter;
/**
*
*/
@property (nonatomic, assign) BOOL consolelogEnable;
/**
* @deprecate
* 退App退abort退
* 5s
* 0abort退
*/
@property (nonatomic, assign) NSUInteger crashAbortTimeout;
/**
* crash
*/
@property (nonatomic, copy) NSString *crashServerUrl;
/// CS_CALLBACK_FLAGS_LUA(0x1) | CS_CALLBACK_FLAGS_JA(0x1 << 1) | CS_CALLBACK_FLAGS_CSHARP(0x1 << 2) | CS_CALLBACK_FLAGS_CRASH(0x1 << 4), default: 0xFFFF
@property (nonatomic, assign) uint32_t callbackFlags;
/**
*
* defalut2, 020
*
*/
@property (nonatomic, assign) int crashProcessTimeout;
/**
* COS 10MB
*
*/
@property (nonatomic, copy) NSString *uploadUserAttchmentFilePath;
@property (nonatomic, copy) NSString *oomAttchmentFilePath;
@property (nonatomic, assign) BOOL ignoreCallSigaltstackFunctionFailed;
@end

View File

@ -0,0 +1,78 @@
//
// CrashSightLog.h
// CrashSight
//
// Copyright (c) 2017年
//
#import <Foundation/Foundation.h>
// Log level for CrashSight Log
typedef NS_ENUM(NSUInteger, CrashSightLogLevel) {
CrashSightLogLevelSilent = 0,
CrashSightLogLevelError = 1,
CrashSightLogLevelWarn = 2,
CrashSightLogLevelInfo = 3,
CrashSightLogLevelDebug = 4,
CrashSightLogLevelVerbose = 5,
};
#pragma mark -
OBJC_EXTERN void CSLog(CrashSightLogLevel level, NSString *format, ...) NS_FORMAT_FUNCTION(2, 3);
OBJC_EXTERN void CSLogv(CrashSightLogLevel level, NSString *format, va_list args) NS_FORMAT_FUNCTION(2, 0);
#pragma mark -
#define CRASHSIGHT_LOG_MACRO(_level, fmt, ...) [CrashSightLog level:_level tag:nil log:fmt, ##__VA_ARGS__]
#define CSLogError(fmt, ...) CRASHSIGHT_LOG_MACRO(CrashSightLogLevelError, fmt, ##__VA_ARGS__)
#define CSLogWarn(fmt, ...) CRASHSIGHT_LOG_MACRO(CrashSightLogLevelWarn, fmt, ##__VA_ARGS__)
#define CSLogInfo(fmt, ...) CRASHSIGHT_LOG_MACRO(CrashSightLogLevelInfo, fmt, ##__VA_ARGS__)
#define CSLogDebug(fmt, ...) CRASHSIGHT_LOG_MACRO(CrashSightLogLevelDebug, fmt, ##__VA_ARGS__)
#define CSLogVerbose(fmt, ...) CRASHSIGHT_LOG_MACRO(CrashSightLogLevelVerbose, fmt, ##__VA_ARGS__)
#pragma mark - Interface
@interface CrashSightLog : NSObject
/**
* @brief
*
* @param level CSLogLevelSilent
*
* @param printConsole NO
*/
+ (void)initLogger:(CrashSightLogLevel) level consolePrint:(BOOL)printConsole;
/**
* @brief CSLogLevelInfo
*
* @param format 30k200
*/
+ (void)log:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2);
/**
* @brief
*
* @param level
* @param message 30k200
*/
+ (void)level:(CrashSightLogLevel) level logs:(NSString *)message;
/**
* @brief
*
* @param level
* @param format 30k200
*/
+ (void)level:(CrashSightLogLevel) level log:(NSString *)format, ... NS_FORMAT_FUNCTION(2, 3);
/**
* @brief
*
* @param level
* @param tag
* @param format 30k200
*/
+ (void)level:(CrashSightLogLevel) level tag:(NSString *) tag log:(NSString *)format, ... NS_FORMAT_FUNCTION(3, 4);
@end

View File

@ -0,0 +1,6 @@
framework module CrashSight {
umbrella header "CrashSight.h"
export *
module * { export * }
}

View File

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyCollectedDataTypes</key>
<array>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypePerformanceData</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<false/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
</array>
</dict>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeCrashData</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<false/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
</array>
</dict>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeDeviceID</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<false/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
</array>
</dict>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeUserID</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<false/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
</array>
</dict>
</array>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryDiskSpace</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>E174.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>35F9.1</string>
</array>
</dict>
</array>
</dict>
</plist>

View File

@ -0,0 +1,106 @@
fileFormatVersion: 2
guid: 865fe01356f9247b7878748577677c77
folderAsset: yes
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
'': Any
second:
enabled: 0
settings:
Exclude Android: 1
Exclude Editor: 1
Exclude Linux: 1
Exclude Linux64: 1
Exclude LinuxUniversal: 1
Exclude OSXUniversal: 1
Exclude Win: 1
Exclude Win64: 1
Exclude iOS: 0
- first:
Android: Android
second:
enabled: 0
settings:
CPU: ARMv7
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
CPU: AnyCPU
DefaultValueInitialized: true
OS: AnyOS
- first:
Facebook: Win
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Facebook: Win64
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Standalone: Linux
second:
enabled: 0
settings:
CPU: x86
- first:
Standalone: Linux64
second:
enabled: 0
settings:
CPU: x86_64
- first:
Standalone: LinuxUniversal
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: OSXUniversal
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Standalone: Win
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Standalone: Win64
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
iPhone: iOS
second:
enabled: 1
settings:
AddToEmbeddedBinaries: true
CompileFlags:
FrameworkDependencies: Security;
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,48 @@
//
// Created by joyfyzhang on 2021/10/18.
//
#ifndef ANDROID_UQMUNITYBRIDGE_H
#define ANDROID_UQMUNITYBRIDGE_H
#ifdef ANDROID
#include "UQMDefine.h"
#include "UQM.h"
#include "UQMUtils.h"
#include "CSLogger.h"
#include <string>
#endif
#ifdef __APPLE__
#include <CrashSightCore/CrashSightCore.h>
#endif
NS_UQM_BEGIN
typedef char* (*UQMRetJsonCallback)(int methodId, int callbackType, int logUploadResult);
class UQMUnityBridge {
public:
static UQMRetJsonCallback SendToUnity;
static void SetBridge(UQMRetJsonCallback bridge);
static char *pInvokeHandleCallback(int methodId, int callbackType, int logUploadResult = 0) {
if (UQMUnityBridge::SendToUnity == NULL) {
UQM_LOG_DEBUG("No callback for unity, please do UQM.Init(); first !");
return NULL;
} else {
return UQMUnityBridge::SendToUnity(methodId, callbackType, logUploadResult);
}
}
};
extern "C" {
void UQM_EXPORT cs_setUnityCallback(UQMRetJsonCallback bridge);
int UQM_EXPORT cs_unityForceCrash();
int UQM_EXPORT cs_unityCrashCallback();
int UQM_EXPORT cs_unityCrashLogCallback();
int UQM_EXPORT cs_unregisterUnityCrashCallback();
}
NS_UQM_END
#endif //ANDROID_UQMUNITYBRIDGE_H

View File

@ -0,0 +1,142 @@
//
// Created by joyfyzhang on 2021/10/19.
//
#ifndef ANDROID_UQMUNITYEXTRA_H
#define ANDROID_UQMUNITYEXTRA_H
#include "UQMUnityBridge.h"
extern "C"
{
///----- UQMCrash
void UQM_EXPORT cs_configCallbackTypeAdapter(int32_t callbackType);
void UQM_EXPORT cs_configGameTypeAdapter(int gameType);
void UQM_EXPORT cs_configAutoReportLogLevelAdapter(int level);
void UQM_EXPORT cs_configDefaultAdapter(const char *channel, const char *version, const char *user, int64_t delay);
void UQM_EXPORT cs_configCrashServerUrlAdapter(const char *serverUrl);
void UQM_EXPORT cs_configDebugModeAdapter(bool enable);
void UQM_EXPORT cs_setDeviceIdAdapter(const char *deviceId);
/**
* deviceId
* @param deviceId
*/
void UQM_EXPORT cs_setCustomizedDeviceIDAdapter(const char *deviceId);
const char* UQM_EXPORT cs_getSDKDefinedDeviceIDAdapter();
void UQM_EXPORT cs_setCustomizedMatchIDAdapter(const char *matchId);
const char* UQM_EXPORT cs_getSDKSessionIDAdapter();
const char* UQM_EXPORT cs_getCrashUuidAdapter();
void UQM_EXPORT cs_setDeviceModelAdapter(const char *deviceModel);
void UQM_EXPORT cs_setCallbackMsgAdapter(const char *msg);
void UQM_EXPORT cs_initWithAppIdAdapter(const char *appId, bool forceOnUiThread);
void UQM_EXPORT cs_logRecordAdapter(int level, const char *message);
void UQM_EXPORT cs_addSceneDataAdapter(const char *key, const char *value);
void UQM_EXPORT cs_reportExceptionAdapter(int type, const char *exceptionName, const char *exceptionMsg,
const char *exceptionStack, const char *extras, const char *paramsJson,
bool quitProgram, int dumpNativeType, const char* errorAttachmentPath);
void UQM_EXPORT cs_setUserIdAdapter(const char *userId);
void UQM_EXPORT cs_setSceneAdapter(const char *sceneId, bool upload);
void UQM_EXPORT cs_setLogPathAdapter(const char *logPath);
void UQM_EXPORT cs_reRegistAllMonitorsAdapter();
void UQM_EXPORT cs_closeAllMonitorsAdapter();
void UQM_EXPORT cs_setAppVersionAdapter(const char *appVersion);
void UQM_EXPORT cs_crashObserverAdapter();
void UQM_EXPORT cs_unregisterCrashObserverAdapter();
void UQM_EXPORT cs_crashLogObserverAdapter();
void UQM_EXPORT cs_reportLogInfo(const char *msgType, const char *msg);
// test api
void UQM_EXPORT cs_testOomCrashAdapter();
void UQM_EXPORT cs_testJavaCrashAdapter();
void UQM_EXPORT cs_testOcCrashAdapter();
void UQM_EXPORT cs_testNativeCrashAdapter();
void UQM_EXPORT cs_testANRAdapter();
void UQM_EXPORT cs_setCatchMultiSignal(bool enable);
void UQM_EXPORT cs_setUnwindExtraStack(bool enable);
long UQM_EXPORT cs_getCrashThreadId();
void UQM_EXPORT cs_setLogcatBufferSize(int size);
void UQM_EXPORT cs_startDumpRoutine(int dumpMode, int startTimeMode, long startTime, long dumpInterval,
int dumpTimes, bool saveLocal, const char *savePath);
void UQM_EXPORT cs_startMonitorFdCount(int interval, int limit, int dumpType);
int UQM_EXPORT cs_getExceptionType(const char *name);
void UQM_EXPORT cs_testUseAfterFreeAdapter();
void UQM_EXPORT cs_setEnableGetPackageInfo(bool enable);
void UQM_EXPORT cs_setServerEnv(const char *serverEnv);
void UQM_EXPORT cs_setEngineInfo(const char *version, const char *buildConfig, const char *language, const char *locale);
void UQM_EXPORT cs_setGpuInfo(const char *version, const char *vendor, const char *renderer);
void UQM_EXPORT cs_enableDetailedPageTracing(bool enable);
void UQM_EXPORT cs_useSavedUserId(bool enable);
bool UQM_EXPORT cs_isLastSessionCrash();
const char* UQM_EXPORT cs_getLastSessionUserId();
bool UQM_EXPORT cs_checkFdCount(int limit, int dumpType, bool upload);
void UQM_EXPORT cs_setOomLogPath(const char *logPath);
void UQM_EXPORT cs_reportJank(int type, const char* exceptionName,
const char* exceptionMsg, const char* exceptionStack,
const char* extInfoJsonStr, int reportInfoOption, const char* jankAttachmentPath);
void UQM_EXPORT cs_processEngineAnr(int type);
void UQM_EXPORT cs_setEngineMainThread();
void UQM_EXPORT cs_reportStuck(int threadId, int maxChecks, int checkInterval,
const char *name, const char *message, const char *extraInfo,
int dumpNativeType, const char *attachPath);
#if __APPLE__
bool cs_showRatingAlertAdapter();
void cs_showAppStoreProductViewAdapter(const char* appid);
#endif
}
#endif //ANDROID_UQMUNITYEXTRA_H

View File

@ -0,0 +1,106 @@
fileFormatVersion: 2
guid: 19fc057f016ee4b3495e1f3f53003a19
folderAsset: yes
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
'': Any
second:
enabled: 0
settings:
Exclude Android: 1
Exclude Editor: 1
Exclude Linux: 1
Exclude Linux64: 1
Exclude LinuxUniversal: 1
Exclude OSXUniversal: 1
Exclude Win: 1
Exclude Win64: 1
Exclude iOS: 0
- first:
Android: Android
second:
enabled: 0
settings:
CPU: ARMv7
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
CPU: AnyCPU
DefaultValueInitialized: true
OS: AnyOS
- first:
Facebook: Win
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Facebook: Win64
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Standalone: Linux
second:
enabled: 0
settings:
CPU: x86
- first:
Standalone: Linux64
second:
enabled: 0
settings:
CPU: x86_64
- first:
Standalone: LinuxUniversal
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: OSXUniversal
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Standalone: Win
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Standalone: Win64
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
iPhone: iOS
second:
enabled: 1
settings:
AddToEmbeddedBinaries: true
CompileFlags:
FrameworkDependencies: Security;
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,46 @@
#ifndef CSLogger_hpp
#define CSLogger_hpp
#include "UQMMacros.h"
#include <stdarg.h>
#ifndef CS_LOG_TAG
#define CS_LOG_TAG "[CrashSightPlugin-Native]"
#endif
// your convenient logger macro
#define CSLoggerDebug(fmt, ...) CSLogger::log(CSLoggerLevel::CSLoggerLevelDebug, CS_LOG_TAG, fmt, ##__VA_ARGS__);
#define UQM_LOG_DEBUG(fmt, ...) CSLogger::log(CSLoggerLevel::CSLoggerLevelDebug, CS_LOG_TAG, fmt, ##__VA_ARGS__)
#define CSLoggerInfo(fmt, ...) CSLogger::log(CSLoggerLevel::CSLoggerLevelInfo, CS_LOG_TAG, fmt, ##__VA_ARGS__);
#define CSLoggerWarn(fmt, ...) CSLogger::log(CSLoggerLevel::CSLoggerLevelWarn, CS_LOG_TAG, fmt, ##__VA_ARGS__);
#define CSLoggerError(fmt, ...) CSLogger::log(CSLoggerLevel::CSLoggerLevelError, CS_LOG_TAG, fmt, ##__VA_ARGS__);
#define UQM_LOG_ERROR(fmt, ...) CSLogger::log(CSLoggerLevel::CSLoggerLevelError, CS_LOG_TAG, fmt, ##__VA_ARGS__)
NS_UQM_BEGIN
typedef enum
{
CSLoggerLevelDebug = 0,
CSLoggerLevelInfo,
CSLoggerLevelWarn,
CSLoggerLevelError,
CSLoggerLevelSilent
} CSLoggerLevel;
class UQM_EXPORT CSLogger
{
private:
static CSLoggerLevel _loggerLevel;
public:
static void setLoggerLevel(CSLoggerLevel loggerLevel);
static void log(CSLoggerLevel loggerLevel, const char *tag, const char *fmt, ...);
static void logv(CSLoggerLevel loggerLevel, const char *tag, const char *fmt, va_list args);
};
NS_UQM_END
#endif /* CSLogger_hpp */

View File

@ -0,0 +1,64 @@
//
// Created by joyfyzhang on 2021/6/13.
//
#ifndef UQM_CRASH_INTERFACE_H
#define UQM_CRASH_INTERFACE_H
#include "UQMMacros.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
*
* @param app_id CrashSightAppID.
* @param unexpected_terminating_detection_enable iOS退Android
* @param debug_mode 线
* @param server_url
*/
void UQM_EXPORT cs_init(const char* app_id, bool unexpected_terminating_detection_enable, bool debug_mode, const char* server_url);
/**
*
* @param level 0-silent, 1-error, 2-warning, 3-info, 4-debug, 5-verbose
* @param tag
* @param log
*/
void UQM_EXPORT cs_log_info(int level, const char* tag, const char* log);
/**
*
* @param key
* @param value
*/
void UQM_EXPORT cs_set_user_value(const char* key, const char* value);
/**
* ID
* @param user_id ID
*/
void UQM_EXPORT cs_set_user_id(const char* user_id);
/**
*
* @param type
* @param exception_name
* @param exception_msg
* @param exception_stack
*/
void UQM_EXPORT cs_report_exception(int type, const char* exception_name, const char* exception_msg, const char* exception_stack, bool is_dump_nativeStack= false);
/**
*
*/
void UQM_EXPORT cs_trigger_crash();
#ifdef __cplusplus
}
#endif
#endif //UQM_CRASH_INTERFACE_H

View File

@ -0,0 +1,28 @@
//
// CrashSightCore.h
// CrashSightCore
//
// Created by 张飞阳 on 2021/6/17.
// Copyright © 2021 joyfyzhang. All rights reserved.
//
#import <CrashSightCore/UQMRename.h>
#import <CrashSightCore/UQMMacros.h>
#import <CrashSightCore/UQMError.h>
#import <CrashSightCore/UQMCompatLayer.h>
#import <CrashSightCore/UQM.h>
#import <CrashSightCore/UQMDefine.h>
#import <CrashSightCore/UQMUtils.h>
#import <CrashSightCore/UQMMacroExpand.h>
#import <CrashSightCore/UQMSingleton.h>
#import <CrashSightCore/UQMLog.h>
#import <CrashSightCore/UQMThread.h>
#import <CrashSightCore/UQMCrashIMPL.h>
#import <CrashSightCore/UQMCrash.h>
#import <CrashSightCore/UQMSynthesizeSingleton.h>
#import <CrashSightCore/UQMUtilsIOS.h>
#import <CrashSightCore/UQMCrashDelegate.h>
#import <CrashSightCore/CrashSightBridge.h>
#import <CrashSightCore/CrashSightMobileAgent.h>

View File

@ -0,0 +1,223 @@
#pragma once
#ifndef GCLOUD_VERSION_CRASHSIGHT
#define GCLOUD_VERSION_CRASHSIGHT "GCLOUD_VERSION_CRASHSIGHT_4.3.8.1084" //用于编译时传入
#endif
#include "UQMMacros.h"
//using namespace UQM;
namespace GCloud {
namespace CrashSight {
enum LogSeverity
{
LogSilent,
LogError,
LogWarning,
LogInfo,
LogDebug,
LogVerbose
};
class UQM_EXPORT CrashSightMobileAgent
{
public:
/// Set game type for Android
/// @param gameType COCOS=1, UNITY=2, UNREAL=3
static void SetGameType(int gameType);
/// configs callback type.
/// @param callbackType 目前是5种类型用5位表示。第一位表示crash第二位表示anr第三位表示u3d c# error第四位表示js第五位表示lua
static void ConfigCallbackType(int32_t callbackType);
/// Configs the default.
/// @param channel channel
/// @param version version
/// @param user user
/// @param delay delay
static void ConfigDefault(const char* channel, const char* version, const char* user, long delay);
/// Configs the crashServerUrl.
/// @param crashServerUrl crashServerUrl
static void ConfigCrashServerUrl(const char* crashServerUrl);
/// Configs the type of the crash reporter and customized log level to upload
/// @param logLevel Off=0,Error=1,Warn=2,Info=3,Debug=4
static void ConfigCrashReporter(int logLevel);
/// configs the debug mode.
/// @param enable If set to true< debug mode.
static void ConfigDebugMode(bool enable);
/// Set deviceId.
/// @param deviceId 设备唯一标识
static void SetDeviceId(const char* deviceId);
/// Set app deviceId.
/// @param deviceId
static void SetCustomizedDeviceID(const char* deviceId);
static void GetSDKDefinedDeviceID(void* data, int len);
static void SetCustomizedMatchID(const char* matchId);
static void GetSDKSessionID(void* data, int len);
/// Set deviceModel.
/// @param deviceModel 手机型号
static void SetDeviceModel(const char* deviceModel);
/// 设置日志绝对路径.
/// @param logPath 日志路径
static void SetLogPath(const char* logPath);
/// Init sdk with the specified appId.
/// @param appId App identifier.
static void InitWithAppId(const char* appId, bool forceOnUiThread);
static void ReportExceptionPRV(int type, const char* exceptionName, const char* exceptionMsg, const char* exceptionStack, const char *extInfo, const char* extInfoJsonStr, bool quit = false, int dumpNativeType = 0, const char* errorAttachmentPath = "");
/// Report Exception
/// @param type type
/// @param name name
/// @param reason reason
/// @param stackTrace stackTrace
/// @param extras extras, json对象序列化字符串
/// @param quit quit
/// @param dumpNativeType 0关闭1调用系统接口dump3minidump
static void ReportException(int type, const char* name, const char* reason, const char* stackTrace, const char* extras, bool quit, int dumpNativeType = 0, const char* errorAttachmentPath = "");
/// Report Exception
/// @param type
/// @param exceptionName
/// @param exceptionMsg
/// @param exceptionStack
/// @param paramsJson map序列化后的JSON字符串
/// @param dumpNativeType 0关闭1调用系统接口dump3minidump
static void ReportExceptionJson(int type, const char* exceptionName, const char* exceptionMsg, const char* exceptionStack, const char* paramsJson, int dumpNativeType = 0, const char* errorAttachmentPath = "");
/// Report log statistics
/// @msgType 消息类型
/// @msg 消息详情
static void ReportLogInfo(const char* msgType, const char* msg);
/// Sets the user identifier.
/// @param userId User identifier.
static void SetUserId(const char* userId);
/// Sets the scene.
/// @param sceneId Scene identifier.
static void SetScene(const char *sceneId, bool upload = false);
/// Adds the scene data.
/// @param key Key
/// @param value Value
static void AddSceneData(const char* key, const char* value);
/// Prints the log.
/// @param level level
/// @param format format
static void PrintLog(LogSeverity level, const char* format, ...);
// unity android
static void CloseCrashReport();
// unity android
static void StartCrashReport();
// unity android
static void RestartCrashReport();
/// Set app version.
/// @param appVersion app version
static void SetAppVersion(const char* appVersion);
/// Catch multiple signal from different thread, and upload information of first signal.
/// @param SetCatchMultiSignal enable
static void SetCatchMultiSignal(bool enable);
/// Unwind at most 256 stack frame, and report last frame even if stack string is full.
/// @param SetUnwindExtraStack enable
static void SetUnwindExtraStack(bool enable);
/// Get crash thread id when crash happens. Return -1 while failed.
static long GetCrashThreadId();
static bool IsLastSessionCrash();
static void GetLastSessionUserId(void* data, int len);
/// Set upload thread num, default 3
static void SetUploadThreadNum(int num);
static void TestOomCrash();
static void TestJavaCrash();
static void TestOcCrash();
static void TestNativeCrash();
static void TestANR();
static void GetCrashUuid(void* data, int len);
static void SetLogcatBufferSize(int size);
static void startDumpRoutine(int dumpMode, int startTimeMode, long startTime, long dumpInterval,
int dumpTimes, bool saveLocal, const char *savePath);
static void startMonitorFdCount(int interval, int limit, int dumpType);
static int getExceptionType(const char *name);
static void testUseAfterFree();
static void setEnableGetPackageInfo(bool enable);
static void setServerEnv(const char *serverEnv);
static void setEngineInfo(const char *version, const char *buildConfig, const char *language, const char *locale);
static void setGpuInfo(const char *version, const char *vendor, const char *renderer);
static void setIsOpengles(bool isOpengles);
static void enableDetailedPageTracing(bool enable);
static void useSavedUserId(bool enable);
static bool checkFdCount(int limit, int dumpType, bool upload);
static void SetOomLogPath(const char *logPath);
static void ReportJank(int type, const char* exceptionName,
const char* exceptionMsg, const char* exceptionStack,
const char* extInfoJsonStr, int reportInfoOption, const char* jankAttachmentPath = nullptr);
static void processEngineAnr(int type);
static void setEngineMainThread();
static void ReportStuck(int threadId, int maxChecks, long checkInterval,
const char *name, const char *message, const char *extraInfo,
int dumpNativeType, const char *attachPath);
private:
static bool mIsInitialized;
static const char* GetCsVersion();
};
}
}

View File

@ -0,0 +1,57 @@
//
// UQM.h
// CrashSight
//
// Created by joyfyzhang on 2020/9/4.
// Copyright © 2020 joyfyzhang. All rights reserved.
//
#ifndef UQM_h
#define UQM_h
#include "UQMMacros.h"
#include "UQMSingleton.h"
#ifdef ANDROID
#include <jni.h>
#endif
NS_UQM_BEGIN
//暂未弄清楚此处的具体用途,故不做替换修改
#ifdef _WIN32
#define UQM_ITOP_DEPRECATED(_version)
#else
#define UQM_ITOP_DEPRECATED(_version) __attribute__((deprecated))
#endif
class UQM : public UQMSingleton<UQM>
{
friend class UQMSingleton<UQM>;
private:
UQM() {
initialized = false;
};
virtual ~UQM();
public:
//JavaVM 是Android JNI使用iOS这里定义一个保证编译通过
#if UQM_PLATFORM_WINDOWS
#define JavaVM void
#else
#ifdef __APPLE__
#define JavaVM void
#endif
#endif
void Initialize(JavaVM *vm);
private:
bool initialized;
};
NS_UQM_END
// #include "UQMRename.h"
#endif /* UQM_h */

View File

@ -0,0 +1,515 @@
//
// UQMCompatLayer.hpp
// Crashot
//
// Created by joyfyzhang on 2020/9/3.
// Copyright © 2020 joyfyzhang. All rights reserved.
//
#ifndef UQMCompatLayer_hpp
#define UQMCompatLayer_hpp
#include <sstream>
#include "UQMMacros.h"
#include "UQMMacroExpand.h"
#if UQM_PLATFORM_WINDOWS
#define uqm_strncpy(deestination,source,sourceLen) \
do { \
strncpy_s(deestination, sourceLen+1, source, sourceLen); \
} while (0)
#define uqm_strncat(deestination,source,sourceLen) \
do {\
strncat_s(deestination, sourceLen+1, source, sourceLen); \
} while (0)
#endif
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4996)
#elif defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated"
#endif
NS_UQM_BEGIN
class UQMString
{
private:
char *data;
unsigned long len;
public:
UQMString() : len(0)
{
data = UQM_SAFE_MALLOC(1, char);
data[0] = '\0';
}
UQMString(const std::string &str)
{
len = str.size();
data = UQM_SAFE_MALLOC(len + 1, char);
strncpy(data, str.c_str(), len);
data[len] = '\0';
}
UQMString(const char *strPtr)
{
if (strPtr == NULL)
{
len = 0;
data = UQM_SAFE_MALLOC(1, char);
data[0] = '\0';
return;
}
len = (unsigned int) strlen(strPtr);
data = UQM_SAFE_MALLOC(len + 1, char);
strncpy(data, strPtr, len);
data[len] = '\0';
}
UQMString(const UQMString &str)
{
len = (unsigned int) str.size();
data = UQM_SAFE_MALLOC(len + 1, char);
strncpy(data, str.c_str(), len);
data[len] = '\0';
}
// 析构函数
~UQMString()
{
UQM_SAFE_FREE(data);
len = 0;
}
// 重载+
UQMString operator+(const UQMString &str) const
{
UQMString newStr;
UQM_SAFE_FREE(newStr.data);
newStr.len = len + (unsigned int) str.size();
newStr.data = UQM_SAFE_MALLOC(newStr.len + 1, char);
strncpy(newStr.data, data, len);
strncat(newStr.data, str.data, str.length());
newStr.data[newStr.len] = '\0';
return newStr;
}
// 重载=
UQMString &operator=(const UQMString &str)
{
if (this == &str)
{
return *this;
}
UQM_SAFE_FREE(data);
len = str.len;
data = UQM_SAFE_MALLOC(len + 1, char);
strncpy(data, str.c_str(), len);
data[len] = '\0';
return *this;
}
// 重载=
UQMString &operator=(const char *strPtr)
{
if (strPtr == NULL)
{
len = 0;
data = UQM_SAFE_MALLOC(1, char);
data[0] = '\0';
return *this;
}
UQM_SAFE_FREE(data);
len = (unsigned int) strlen(strPtr);
data = UQM_SAFE_MALLOC(len + 1, char);
strncpy(data, strPtr, len);
data[len] = '\0';
return *this;
}
// 重载=
UQMString &operator=(const std::string &str)
{
UQM_SAFE_FREE(data);
len = str.length();
data = UQM_SAFE_MALLOC(len + 1, char);
strncpy(data, str.c_str(), len);
data[len] = '\0';
return *this;
}
// 重载+=
UQMString &operator+=(const UQMString &str)
{
len += str.len;
char *new_data = UQM_SAFE_MALLOC(len + 1, char);
strncpy(new_data, data, len);
strncat(new_data, str.data,str.size());
UQM_SAFE_FREE(data);
data = new_data;
data[len] = '\0';
return *this;
}
// 重载==
inline bool operator==(const UQMString &str) const
{
if (len != str.len)
{
return false;
}
return strcmp(data, str.data) == 0;
}
// 获取长度
inline size_t size() const
{
return len;
}
inline size_t length() const
{
return len;
}
const std::string toString() const
{
if (data)
{
return data;
}
return "";
}
bool empty() const
{
return size() <= 0;
}
// 获取C字符串
inline const char *c_str() const
{
return data;
}
};
class UQMKVPair
{
public:
UQMString key;
UQMString value;
#if UQM_PLATFORM_WINDOWS
#else
UQM_AutoParser("", O(key, value));
#endif
};
// 重新定义vector
template<typename T, unsigned int SPARE_CAPACITY = 16>
class UQMVector
{
public:
//将构造函数声明为explicit ,是为了抑制由构造函数定义的隐式转换
explicit UQMVector(unsigned long initSize = 0) : vectorSize(0), vectorCapacity(
(unsigned int) initSize + SPARE_CAPACITY), objects(NULL)
{
objects = UQM_SAFE_MALLOC(initSize + SPARE_CAPACITY, T);
}
UQMVector(const UQMVector &rhs) : objects(NULL)
{
vectorSize = rhs.vectorSize;
vectorCapacity = rhs.vectorCapacity;
objects = UQM_SAFE_MALLOC(vectorCapacity, T);
for (unsigned int k = 0; k < vectorSize; k++)
{
objects[k] = rhs.objects[k];
}
}
~UQMVector()
{
for (unsigned int i = 0; i < vectorSize; i++)
{
objects[i].~T();
}
UQM_SAFE_FREE(objects);
}
const UQMVector &operator=(const UQMVector &rhs)
{
if (this != &rhs)
{
for (unsigned int i = 0; i < vectorSize; i++)
{
objects[i].~T();
}
UQM_SAFE_FREE(objects);
vectorSize = rhs.vectorSize;
vectorCapacity = rhs.vectorCapacity;
objects = UQM_SAFE_MALLOC(vectorCapacity, T);
for (unsigned int k = 0; k < vectorSize; k++)
{
objects[k] = rhs.objects[k];
}
}
return *this;
}
const UQMVector &operator=(const typename std::vector<T> &rhs)
{
if (!rhs.empty())
{
for (unsigned int i = 0; i < vectorSize; i++)
{
objects[i].~T();
}
UQM_SAFE_FREE(objects);
vectorSize = rhs.size();
vectorCapacity = rhs.capacity();
objects = UQM_SAFE_MALLOC(vectorCapacity, T);
for (unsigned int k = 0; k < vectorSize; k++)
{
objects[k] = rhs[k];
}
}
return *this;
}
// 如果index错误直接返回0的数据
T &operator[](int index)
{
if (index < 0 || index >= vectorSize)
{
return objects[0];
}
return objects[index];
}
const T &operator[](int index) const
{
return objects[index];
}
//检测是否需要扩容
void reserve()
{
reserve(vectorSize);
}
// 扩容数据
void reserve(unsigned int newSize)
{
if (vectorCapacity > newSize)
{
return;
}
unsigned int newCapacity = newSize * 2 + 1;
T *oldArr = objects;
objects = UQM_SAFE_MALLOC(newCapacity, T);
for (unsigned int k = 0; k < vectorSize; k++)
{
objects[k] = oldArr[k];
}
vectorCapacity = newCapacity;
for (unsigned int i = 0; i < vectorSize; i++)
{
oldArr[i].~T();
}
UQM_SAFE_FREE(oldArr); // 删除原来的数据
}
unsigned int size() const
{
return vectorSize;
}
unsigned int capacity() const
{
return vectorCapacity;
}
bool empty() const
{
return vectorSize == 0;
}
bool find(const T &t) const
{
for (int i = 0; i < vectorSize; i++)
{
if (objects[i] == t)
{
return true;
}
}
return false;
}
void resize(unsigned int newSize)
{
reserve(newSize);
vectorSize = newSize;
}
void push_back(const T &obj)
{
reserve(); // 检测容器大小
objects[vectorSize++] = obj;
}
void pop_back()
{
objects[vectorSize].~T();
vectorSize--;
}
const T &back() const
{
return objects[vectorSize - 1];
}
const T *begin()
{
return &objects[0];
}
T *end()
{
return &objects[vectorSize];
}
bool clear()
{
for (int i = 0; i < vectorSize; i++)
{
objects[i].~T();
}
vectorSize = 0;
UQM_SAFE_FREE(objects);
objects = UQM_SAFE_MALLOC(SPARE_CAPACITY, T);
vectorCapacity = SPARE_CAPACITY;
return true;
}
const T *end() const
{
return &objects[vectorSize];
}
std::string toString()
{
std::stringstream out;
out << "Vector length:" << size() << ",capacity:" << capacity() << std::endl;
for (int i = 0; i < vectorSize; i++)
{
out << "objects[" << i << "]:" << objects[i] << std::endl;
}
return out.str();
}
typedef T *iterator;
private:
unsigned int vectorSize;
unsigned int vectorCapacity;
T *objects;
};
class UQMRetAdapter
{
public:
void convert(bool &val, const bool &innerVal);
void convert(double &val, const double &innerVal);
void convert(float &val, const float &innerVal);
void convert(int &val, const int &innerVal);
// void convert(long &val, const long &innerVal);
void convert(int64_t &val, const int64_t &innerVal);
void convert(std::string &val, const UQMString &innerVal)
{
val = innerVal.c_str();
}
void convert(UQMString &innerVal, const std::string &val)
{
innerVal = val;
}
void convert(std::map<std::string, std::string> &val, const UQMVector<UQMKVPair> &innerVal)
{
for (unsigned int i = 0; i < innerVal.size(); i++)
{
val.insert(std::make_pair(innerVal[i].key.c_str(), innerVal[i].value.c_str()));
}
}
template<typename OutTypeRet, typename InnerTypeRet>
void convert(std::vector<OutTypeRet> &val, const UQMVector<InnerTypeRet> &innerVal)
{
size_t s = innerVal.size();
val.resize(s);
for (unsigned int i = 0; i < s; ++i)
{
convert(val[i], innerVal[i]); // operator[](size_t)
}
}
template<typename OutTypeRet, typename InnerTypeRet>
void convert(OutTypeRet &outTypeRet, const InnerTypeRet &innerTypeRet)
{
#if UQM_PLATFORM_WINDOWS
#else
outTypeRet.innerRetConvert(*this, innerTypeRet);
#endif
};
};
class UQM_EXPORT UQMCompatManager
{
public:
template<typename OutTypeRet, typename InnerTypeRet>
static bool compatConvert(OutTypeRet &outTypeRet, const InnerTypeRet &innerTypeRet)
{
UQMRetAdapter ret;
ret.convert(outTypeRet, innerTypeRet);
return true;
}
};
NS_UQM_END
#ifdef _MSC_VER
#pragma warning(pop)
#elif defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
#endif /* UQMCompatLayer_hpp */

View File

@ -0,0 +1,243 @@
//
// UQMCrash.hpp
// Version: 4.3.8(1084)
// Created by joyfyzhang on 2020/9/3.
// Copyright © 2020 joyfyzhang. All rights reserved.
//
#ifndef UQMCrash_h
#define UQMCrash_h
#include "UQMDefine.h"
#include "CrashSightMobileAgent.h"
NS_UQM_BEGIN
typedef enum {
CRASH_TYPE_NATIVE = 2,
CRASH_TYPE_U3D = 3,
CRASH_TYPE_ANR = 4,
CRASH_TYPE_JS = 5,
CRASH_TYPE_LUA = 6,
}UQMCrashType;
class UQM_EXPORT UQMCrashRet : public UQMBaseRet {
public:
int maxDataLen;
char* data;
};
class UQM_EXPORT UQMCrashObserver
{
public:
//新增一个虚析构函数 不然 UE4 报错
virtual ~UQMCrashObserver() {};
virtual long OnCrashExtraDataNotify(const UQMInnerCrashRet& crashRet) {
return 0;
};
virtual const char* OnCrashExtraMessageNotify(int crashType) {
return NULL;
};
};
class UQM_EXPORT UQMCrashLogObserver
{
public:
//新增一个虚析构函数 不然 UE4 报错
virtual ~UQMCrashLogObserver() {};
// 设置日志路径回调
virtual const char* OnCrashSetLogPathNotify(int crashType) {
return NULL;
};
// 通知日志上传结果回调
virtual void OnCrashLogUploadResultNotify(int crashType, int result) {
};
};
class UQM_EXPORT UQMCrash : public GCloud::CrashSight::CrashSightMobileAgent
{
private:
static std::map<int, char*> retMsg;
#if !UQM_PLATFORM_WINDOWS
static pthread_mutex_t mutex;
#endif
static void CrashDataObserver(const UQMInnerCrashRet& crashRet, const char* seqID);
static void CrashMessageObserver(const UQMInnerCrashRet& crashRet, const char* seqID);
static void CrashSetLogPathObserver(const UQMInnerCrashRet& crashRet, const char* seqID);
static void CrashLogUploadResultObserver(const UQMInnerCrashRet& crashRet, const char* seqID);
static UQMCrashObserver* mCrashObserver;
static UQMCrashLogObserver* mCrashLogObserver;
~UQMCrash();
static void SetPRVCrashObserver(UQMInnerRetCallbackClass<UQMInnerCrashRet>::UQMInnerRetCallback crashObserver);
static void SetExtraMessageCrashObserver(UQMInnerRetCallbackClass<UQMInnerCrashRet>::UQMInnerRetCallback crashObserver);
static void SetLogPathObserver(UQMInnerRetCallbackClass<UQMInnerCrashRet>::UQMInnerRetCallback crashObserver);
static void SetLogUploadResultObserver(UQMInnerRetCallbackClass<UQMInnerCrashRet>::UQMInnerRetCallback crashObserver);
public:
static void SetCrashObserver(UQMCrashObserver* crashObserver);
static void SetCrashLogObserver(UQMCrashLogObserver* crashObserver);
/**
*
* @param callbackType 55crashanru3d c# errorjslua
* u3d c# error(type=4), callbackType=0b11011
*/
static void ConfigCallbackTypeBeforeInit(int32_t callbackType);
/**
*
* @param timeout <=0
*/
static void ConfigCrashHandleTimeout(int32_t timeout);
static void Init(const UQMString& appId, bool unexpectedTerminatingDetectionEnable, bool debugMode, const UQMString& serverUrl);
/**
* ,, APP.
*
* @param level 0-silent, 1-error,2-warning3-info4-debug5-verbose
* @param tag
* @param log
*/
static void LogInfo(int level, const UQMString& tag, const UQMString& log);
/**
*
* @param key
* @param value
*/
static void SetUserValue(const UQMString& key, const UQMString& value);
/**
* ID
* @param userId ID
*/
static void SetUserId(const UQMString& userId);
/**
* App ID
* @param appId ID
*/
static void SetAppId(const UQMString& appId);
/**
*
* @param appId ID
*/
static void EntrySubMap(const UQMString& appId);
/**
*
* @param userSceneTag
*/
static void SetUserSceneTag(const UQMString& userSceneTag, bool upload = false);
static void SetCurrentScene(int sceneId);
static void ReportExceptionPRV(int type, const UQMString& exceptionName, const UQMString& exceptionMsg, const UQMString& exceptionStack, const UQMVector<UQMKVPair>& extInfo, const UQMString& extInfoJsonStr, bool quit = false, int dumpNativeType = 0);
/**
* UQM
* @param type 3-cocoa 4-c# 5-JS 6-Lua, 7-
* type=7,exceptionName,exceptionMsg
* @param exceptionName
* @param exceptionMsg
* @param exceptionStack
* @param extInfo
* @param dumpNativeType 01dump3minidump
*/
static void ReportException(int type, const UQMString& exceptionName, const UQMString& exceptionMsg, const UQMString& exceptionStack, std::map<std::string, std::string>& extInfo, int dumpNativeType = 0)
{
UQMVector<UQMKVPair> tmp;
std::map<std::string, std::string>::iterator it = extInfo.begin();
for (; it != extInfo.end(); it++)
{
UQMKVPair kvPair;
kvPair.key = (*it).first;
kvPair.value = (*it).second;
tmp.push_back(kvPair);
}
ReportExceptionPRV(type, exceptionName, exceptionMsg, exceptionStack, tmp,
nullptr, false, dumpNativeType);
}
/**
* UQM: cmap
* @param type 3-cocoa 4-c# 5-JS 6-Lua
* @param exceptionName
* @param exceptionMsg
* @param exceptionStack
* @param dumpNativeType 01dump3minidump
*/
static void ReportException(int type, const UQMString& exceptionName, const UQMString& exceptionMsg, const UQMString& exceptionStack, int dumpNativeType = 0)
{
UQMVector<UQMKVPair> extInfo;
ReportExceptionPRV(type, exceptionName, exceptionMsg, exceptionStack, extInfo, nullptr, false, dumpNativeType);
}
/**
*
* @param isAppForeground
*/
static void SetIsAppForeground(bool isAppForeground);
static void SetAppVersion(const UQMString& appVersion);
static void SetCallBackMsg(const UQMString &data);
// GameAgent
static void InitWithAppId(const UQMString& appId);
static void ConfigDefaultBeforeInit(const UQMString& channel, const UQMString& version, const UQMString& user, long delay);
static void ConfigCrashServerUrlBeforeInit(const UQMString& crashServerUrl);
static void ConfigCrashReporterLogLevelBeforeInit(int logLevel);
static void ConfigDebugModeBeforeInit(bool enable);
static void SetDeviceId(const UQMString& deviceId);
static void SetCustomizedDeviceID(const UQMString& deviceId);
static void SetCustomizedMatchID(const UQMString& matchId);
static void SetDeviceModel(const UQMString& deviceModel);
static void SetLogPath(const UQMString& logPath);
static void ReportException(int type, const UQMString& name, const UQMString& reason, const UQMString& stackTrace, const UQMString& extras, bool quit, int dumpNativeType = 0)
{
UQMVector<UQMKVPair> tmp;
UQMKVPair kvPair;
kvPair.key = "Extra";
kvPair.value = extras;
tmp.push_back(kvPair);
ReportExceptionPRV(type, name, reason, stackTrace, tmp, nullptr, quit, dumpNativeType);
}
static void ReportExceptionJson(int type, const UQMString& exceptionName, const UQMString& exceptionMsg, const UQMString& exceptionStack, const UQMString& paramsJson, int dumpNativeType = 0)
{
UQMVector<UQMKVPair> tmp;
ReportExceptionPRV(type, exceptionName, exceptionMsg, exceptionStack, tmp, paramsJson,
false, dumpNativeType);
}
static void LogRecord(int level, const UQMString& message);
};
NS_UQM_END
#endif /* UQMCrash_h */

View File

@ -0,0 +1,109 @@
//
// UQMCrashDelegate.h
// UQMCore
//
// Created by joyfyzhang on 2021/1/8.
// Copyright © 2021 joyfyzhang. All rights reserved.
//
#ifndef UQMCrashDelegate_h
#define UQMCrashDelegate_h
#import <Foundation/Foundation.h>
@protocol UQMCrashDelegate <NSObject>
@required
- (void)configCallbackTypeBeforeInit: (int32_t)callbackType;
- (void)configCrashHandleTimeout: (int32_t)timeout;
- (void)initCrashReport:(NSString *)appId unexpectedTerminatingDetectionEnable:(bool)unexpectedTerminatingDetectionEnable debugMode:(bool)debugMode serverUrl:(NSString *)serverUrl;
@optional
- (void)reportLog:(int)level tag:(NSString *)tag log:(NSString *)log;
- (void)setUserData:(NSString *)key value:(NSString *)value;
- (void)setUserId: (NSString *)userId;
- (void)setAppId: (NSString *)appId;
- (void)setUserSceneTag: (NSString *)userSceneTag isUpload:(bool)upload;
- (void)reportException:(int)type exceptionName:(NSString *)exceptionName
exceptionMsg:(NSString *)exceptionMsg
exceptionStack:(NSString *)exceptionStack
extInfo:(NSDictionary *)extInfo
extInfoJsonStr:(NSString *)extInfoJsonStr
quit:(bool)quit
dumpNativeType:(int)dumpNativeType
errorAttachmentPath:(NSString *)errorAttachmentPath;
-(void)reportLogInfo:(NSString*)msgType msg:(NSString*)msg;
- (void)setIsAppForeground: (bool)isAppForeground;
- (void)setAppVersion: (NSString *)appVersion;
// agent
- (void)initWithAppId:(NSString *) appId;
- (void)configCrashServerUrlBeforeInit: (NSString *)serverUrl;
- (void)configDefaultBeforeInit: (NSString *)channel version:(NSString *)version user:(NSString *)user delay:(long)delay;
- (void)configCrashReporterLogLevelBeforeInit: (int)logLevel;
- (void)configDebugModeBeforeInit: (bool) enable;
- (void)logRecord: (int)level message: (NSString *)message;
- (void)setLogPath: (NSString *)logPath;
-(void)closeCrashReport;
-(void)reregisterCrashHandler;
- (long)getCrashThreadId;
- (void)setAppDeviceId: (NSString *)deviceId;
-(NSString*)getBackendDeviceId;
- (void)setCustomizedMatchID: (NSString *)matchId;
-(NSString*)getSDKSessionID;
-(BOOL)isLastSessionCrash;
-(NSString*)getLastSessionUserId;
-(int)getExceptionType:(NSString *)name;
-(void)setServerEnv:(NSString *)serverEnv;
-(void)setEngineInfo:(NSString *)version buildConfig:(NSString *)buildConfig language:(NSString *)language locale:(NSString *)locale;
- (void)enableDetailedPageTracing: (bool) enable;
- (void)useSavedUserId: (bool) enable;
- (void)setOomLogPath: (NSString *)logPath;
-(void)reportJank:(int)type exceptionName:(NSString *)name exceptionMsg:(NSString *) msg exceptionStack:(NSString *)stack extInfoJsonStr:(NSString *)extra reportInfoOption:(int)reportInfoOption jankAttachmentPath:(NSString *)attachPath;
-(void)reportStuckWithThreadIndex:(int)threadIndex
maxChecks:(int)maxChecks
checkInterval:(NSTimeInterval)checkInterval
name:(NSString *)name
message:(NSString *)message
extraInfo:(NSString *)extraInfo
dumpNativeType:(int)dumpNativeType
attachPath:(NSString *)attachPath;
@end
#endif /* UQMCrashDelegate_h */

View File

@ -0,0 +1,158 @@
//
// UQMCrashIMPL.h
// CrashSight
//
// Created by joyfyzhang on 2020/9/4.
// Copyright © 2020 joyfyzhang. All rights reserved.
//
#ifndef UQMCrashIMPL_h
#define UQMCrashIMPL_h
#include "UQMDefine.h"
#include "UQMSingleton.h"
NS_UQM_BEGIN
class UQMCrashIMPL : public UQMSingleton<UQMCrashIMPL>
{
friend class UQMSingleton<UQMCrashIMPL>;
public:
static void ConfigCallbackTypeBeforeInit(const std::string& channel, int32_t callbackType);
static void ConfigCrashHandleTimeout(const std::string& channel, int32_t timeout);
static bool Init(const std::string& channel, const std::string& appId, bool unexpectedTerminatingDetectionEnable, bool debugMode, const std::string& serverUrl);
static void LogInfo(const std::string& channel, int level, const std::string& tag, const std::string& log);
static void SetUserValue(const std::string& channel, const std::string& key, const std::string& value);
static void SetUserId(const std::string& channel, const std::string& userId);
static void SetAppId(const std::string& channel, const std::string& appId);
static void SetUserSceneTag(const std::string& channel, const std::string& userSceneTag, bool upload);
static void ReportException(const std::string& channel, int type, const std::string& exceptionName, const std::string& exceptionMsg, const std::string& exceptionStack, const UQMVector<UQMKVPair> &extInfo, const std::string& extInfoJsonStr, bool quit= false, int dumpNativeType= 0, const std::string& errorAttachmentPath = "");
static void ReportLogInfo(const std::string& msgType, const std::string& msg);
#ifdef ANDROID
static jobject convert(const std::map<std::string, std::string> &data);
#endif
static void SetIsAppForeground(const std::string& channel, bool isAppForeground);
static void SetAppVersion(const std::string& channel, const std::string& appVersion);
//测试接口
static void TestOomCrash(const std::string& channel);
static void TestJavaCrash(const std::string& channel);
static void TestOcCrash(const std::string& channel);
static void TestNativeCrash(std::string channel) {
UQM_LOG_DEBUG("TestNativeCrash channel = %s", channel.c_str());
abort();
}
static void TestANR(const std::string& channel);
//agent
static bool InitWithAppId (const std::string& channel, const std::string& appId, bool forceOnUiThread);
static void SetGameType(const std::string& channel, int gameType);
static void ConfigDefaultBeforeInit(const std::string& channel, const std::string& appChannel, const std::string& version, const std::string& user, long delay);
static void ConfigCrashServerUrlBeforeInit(const std::string& channel, const std::string& serverUrl);
static void ConfigCrashReporterLogLevelBeforeInit(const std::string& channel, int logLevel);
static void ConfigDebugModeBeforeInit(const std::string& channel, bool enable);
static void SetDeviceId(const std::string& channel, const std::string& deviceId);
static void SetAppDeviceId(const std::string& channel, const std::string& deviceId);
static std::string GetBackendDeviceId(const std::string& channel);
static void SetCustomizedMatchID(const std::string& channel, const std::string& matchId);
static std::string GetSDKSessionID(const std::string& channel);
static void SetDeviceModel(const std::string& channel, const std::string& deviceModel);
static void SetLogPath(const std::string& channel, const std::string& logPath);
static void LogRecord (const std::string& channel, int level, const std::string& message);
static void CloseCrashReport(const std::string& channel);
static void StartCrashReport(const std::string& channel);
static void SetCatchMultiSignal(const std::string& channel, bool enable);
static void SetUnwindExtraStack(const std::string& channel, bool enable);
static long GetCrashThreadId(const std::string& channel);
static std::string GetCrashUuid(const std::string &channel);
static bool IsLastSessionCrash(const std::string& channel);
static std::string GetLastSessionUserId(const std::string& channel);
static void SetUploadThreadNum(const std::string& channel, int num);
static void SetLogcatBufferSize(const std::string &channel, int size);
static void startDumpRoutine(const std::string& channel, int dumpMode, int startTimeMode, long startTime,
long dumpInterval, int dumpTimes, bool saveLocal, const std::string& savePath);
static void startMonitorFdCount(const std::string& channel, int interval, int limit, int dumpType);
static int getExceptionType(const std::string& channel, const std::string& name);
static void testUseAfterFree(const std::string &channel);
static void setEnableGetPackageInfo(const std::string& channel, bool enable);
static void setServerEnv(const std::string& channel, const std::string& serverEnv);
static void setEngineInfo(const std::string& channel, const std::string& version, const std::string& buildConfig, const std::string& language, const std::string& locale);
static void setGpuInfo(const std::string& channel, const std::string& version, const std::string& vendor, const std::string& renderer);
static void setIsOpengles(const std::string& channel, bool isOpengles);
static void enableDetailedPageTracing(const std::string& channel, bool enable);
static void useSavedUserId(const std::string& channel, bool enable);
static bool checkFdCount(const std::string& channel, int limit, int dumpType, bool upload);
static void SetOomLogPath(const std::string& channel, const std::string& logPath);
static void ReportJank(const std::string& channel, int type, const std::string& exceptionName,
const std::string& exceptionMsg, const std::string& exceptionStack,
const std::string& extInfoJsonStr, int reportInfoOption, const std::string& jankAttachmentPath);
static void processEngineAnr(const std::string& channel, int type);
static void setEngineMainThread(const std::string& channel);
static void ReportStuck(const std::string& channel, int threadId, int maxChecks, long checkInterval,
const std::string& name, const std::string& message, const std::string& extraInfo,
int dumpNativeType, const std::string& attachPath);
private:
UQMCrashIMPL() {}
static void CallFunction(const std::string& channel, const std::string& functionName, bool enable);
static long CallLongFunction(const std::string& channel, const std::string& functionName);
};
NS_UQM_END
#endif /* UQMCrashIMPL_h */

View File

@ -0,0 +1,269 @@
//
// UQMDefine.hpp
// CrashSight
//
// Created by joyfyzhang on 2020/9/3.
// Copyright © 2020 joyfyzhang. All rights reserved.
//
#ifndef UQMDefine_hpp
#define UQMDefine_hpp
#include <stdio.h>
#include <string>
#include <vector>
#include <ostream>
#include "UQMMacros.h"
#include "UQMMacroExpand.h"
#include "UQMCompatLayer.h"
#include "CSLogger.h"
#define CS_SDK_DEVICE_ID_LEN 64
#define CS_SDK_USER_ID_LEN 64
NS_UQM_BEGIN
typedef enum UQMMethodName {
kUQMMethodNameUndefine = 000,
kUQMMethodNameCrashExtraData = 1011,
kUQMMethodNameCrashExtraMessage = 1012,
kUQMMethodNameCrashSetLogPath = 1013,
kUQMMethodNameCrashLogUploadResult = 1014,
} UQMMethodName;
typedef enum UQMObserverID
{
kUQMObserverIDWakeUp = 107,
}UQMObserverID;
class UQM_EXPORT UQMBaseRet {
public:
// 标记是从哪个方法过来
int methodNameID;
// UQM 返回码,详情可参考 UQMError.h
int retCode;
// UQM 描述信息
std::string retMsg;
// 第三方渠道返回码
int thirdCode;
// 第三方渠道描述信息
std::string thirdMsg;
// 扩展字段,保留
std::string extraJson;
// 构造函数对外使用,必须包含在外部调用,否则会 crash
UQMBaseRet();
// 构造函数对外使用,必须包含在外部调用,否则会 crash
UQMBaseRet(int code);
// 构造函数对外使用,必须包含在外部调用,否则会 crash
UQMBaseRet(int code, int tCode, std::string tMsg);
#if UQM_PLATFORM_WINDOWS
#else
UQM_AutoParser("com.uqm.crashsight.core.api.UQMRet", A(thirdCode, "ret"), A(thirdMsg, "msg"),
O(methodNameID, retCode, retMsg, extraJson));
#endif
};
/**
*
*/
class UQM_EXPORT UQMInnerBaseRet
{
public:
// 标记是从哪个方法过来
int methodNameID;
// UQM 返回码,详情可参考 UQMError.h
int retCode;
// UQM 描述信息
UQMString retMsg;
// 第三方渠道返回码
int thirdCode;
// 第三方渠道描述信息
UQMString thirdMsg;
// 扩展字段,保留
UQMString extraJson;
// 回调类型
int crashType{};
// 构造函数
UQMInnerBaseRet();
UQMInnerBaseRet(int retCode);
UQMInnerBaseRet(int retCode, int methodID);
UQMInnerBaseRet(int retCode, int thirdCode, const UQMString& thirdMsg);
UQMInnerBaseRet(int retCode, UQMString retMsg, int thirdCode, const UQMString& thirdMsg);
#if UQM_PLATFORM_WINDOWS
#else
UQM_AutoParser("com.uqm.crashsight.core.api.UQMRet", A(thirdCode, "ret"),
A(thirdMsg, "msg"), O(methodNameID, retCode, retMsg, extraJson));
#endif
};
class UQMInnerCrashRet : public UQMInnerBaseRet
{
public:
char *data{};
int maxDataLen{};
int *dataLen{};
UQMInnerCrashRet();
#if UQM_PLATFORM_WINDOWS
#else
UQM_AutoParser("com.uqm.crashsight.core.api.crash.UQMCrashRet",
A(thirdCode, "ret"), A(thirdMsg, "msg"),
A(extraJson, "extra"), O(retCode, retMsg, methodNameID),
O(methodNameID));
#endif
};
template<typename RetType>
class UQMInnerRetCallbackClass
{
public:
typedef void (*UQMInnerRetCallback)(const RetType &ret, const char *seqID);
};
template<typename RetType>
class UQMCallBackParams
{
public:
RetType mRet;
unsigned int mObserverID;
UQMString mSeqID;
UQMCallBackParams(const RetType &ret, unsigned int observerID, UQMString seqID): mRet(ret), mObserverID(observerID), mSeqID(seqID){};
};
void UQMInnerObserverHolderDispatch(void (*callback)(int result, void *args), void *context);
template<typename RetType>
class UQMInnerObserverHolder
{
private :
static std::map<int, typename UQMInnerRetCallbackClass<RetType>::UQMInnerRetCallback> mObserverHolder;
static std::map<std::string, UQMCallBackParams<RetType> > mTaskParamsHolder;
static void cacheTask(std::string mSeqID, UQMCallBackParams<RetType> taskParams)
{
if (mSeqID.empty()){
UQM_LOG_DEBUG("cacheTask failed for mSeqID is empty");
return;
}
mTaskParamsHolder.insert(std::make_pair(mSeqID, taskParams));
UQM_LOG_DEBUG("mTaskParamsHolder after insert %s", mSeqID.c_str());
}
static void commitCacheTask()
{
typename std::map<std::string, UQMCallBackParams<RetType> >::iterator iter;
for (iter = mTaskParamsHolder.begin(); iter != mTaskParamsHolder.end(); ){
UQMCallBackParams<RetType> taskParam = iter->second;
if(CommitCacheToTaskQueue(taskParam.mRet, taskParam.mObserverID, taskParam.mSeqID)){
mTaskParamsHolder.erase(iter++);
UQM_LOG_DEBUG("mTaskParamsHolder size: %lu, after erase %s", (unsigned long)mTaskParamsHolder.size(), taskParam.mSeqID.c_str());
} else {
++iter;
}
}
// UQM_LOG_DEBUG("mTaskParamsHolder size: %lu, after commitCacheTask", (unsigned long)mTaskParamsHolder.size());
}
public:
static void CacheObserver(const unsigned int mObserverID, typename UQMInnerRetCallbackClass<RetType>::UQMInnerRetCallback observer)
{
if (mObserverHolder.find(mObserverID) != mObserverHolder.end())
{
// 如果已经存在就删除原来的 key保证 key 对应的 value 是最新
mObserverHolder.erase(mObserverID);
}
mObserverHolder.insert(std::make_pair(mObserverID, observer));
commitCacheTask();
}
static void CommitToTaskQueueBackRet(const RetType &ret, const unsigned int observerID, const UQMString &seqID)
{
if (mObserverHolder.find(observerID) != mObserverHolder.end())
{
UQMInnerCrashRet innerCrashRet = static_cast<UQMInnerCrashRet>(ret);
//UQM_LOG_DEBUG("innerCrashRet %d %s %p %d", observerID, seqID.c_str(), innerCrashRet.data, innerCrashRet.maxDataLen);
mObserverHolder[observerID](ret, seqID.c_str());
}
}
static void CommitToTaskQueue(const RetType &ret, const unsigned int observerID, const UQMString &seqID)
{
UQMCallBackParams<RetType> *params = new UQMCallBackParams<RetType>(ret, observerID, seqID);
if(mObserverHolder.find(params->mObserverID) == mObserverHolder.end()){ // 当前没有setObserver缓存回调
UQM_LOG_DEBUG("Cache ObserverID %d", observerID);
UQMCallBackParams<RetType> taskParams(params->mRet, params->mObserverID, params->mSeqID);
cacheTask(params->mSeqID.toString(), taskParams);
UQM_SAFE_DELETE(params);
} else if (kUQMObserverIDWakeUp == observerID){ //wakeup 回调直接回调
UQM_LOG_DEBUG("CallbackOnMainThread %d", observerID);
CallbackOnMainThread(-1, params);
} else {
UQM_LOG_DEBUG("DispatchAsyncMainThread %d", observerID);
UQMInnerObserverHolderDispatch(CallbackOnMainThread, params);
}
}
static bool CommitCacheToTaskQueue(const RetType &ret, const unsigned int observerID, const UQMString &seqID){
UQMCallBackParams<RetType> *params = new UQMCallBackParams<RetType>(ret, observerID, seqID);
if(mObserverHolder.find(params->mObserverID) != mObserverHolder.end()){
UQM_LOG_DEBUG("DispatchAsyncMainThread %d", observerID);
UQMInnerObserverHolderDispatch(CallbackOnMainThread, params);
return true;
}
UQM_SAFE_DELETE(params);
return false;
}
static void CallbackOnMainThread(int ret, void *args)
{
UQMCallBackParams<RetType> *params = (UQMCallBackParams<RetType> *)args;
if (mObserverHolder.find(params->mObserverID) != mObserverHolder.end())
{
UQM_LOG_DEBUG("observer address %p of observerID : %d", mObserverHolder[params->mObserverID], params->mObserverID);
mObserverHolder[params->mObserverID](params->mRet, params->mSeqID.c_str());
}
else
{
UQM_LOG_DEBUG("can not get inner callback for %u, make sure you have define", params->mObserverID);
}
UQM_SAFE_DELETE(params);
}
};
template<class RetType> std::map<int, typename UQMInnerRetCallbackClass<RetType>::UQMInnerRetCallback> UQMInnerObserverHolder<RetType>::mObserverHolder;
template<class RetType> std::map<std::string, UQMCallBackParams<RetType> > UQMInnerObserverHolder<RetType>::mTaskParamsHolder;
#ifdef ANDROID
typedef void (*FuncRunOnUIDelegate)(void *args);
#endif
NS_UQM_END
#endif /* UQMDefine_hpp */

View File

@ -0,0 +1,88 @@
//
// UQMLog.hpp
// Crashot
//
// Created by joyfyzhang on 2020/9/3.
// Copyright © 2020 joyfyzhang. All rights reserved.
//
#ifndef UQMError_hpp
#define UQMError_hpp
#include "UQMMacros.h"
NS_UQM_BEGIN
class UQMError
{
public:
/** 未知错误 */
static const int UNKNOWN = -1;
static const int SUCCESS = 0;
static const int NO_ASSIGN = 1; /** 没有赋值 */
static const int CANCEL = 2;
static const int SYSTEM_ERROR = 3;
static const int NETWORK_ERROR = 4;
static const int UQM_SERVER_ERROR = 5; // UQM 后台返回错误,参考第三方错误码
static const int TIMEOUT = 6;
static const int NOT_SUPPORT = 7;
static const int OPERATION_SYSTEM_ERROR = 8;
static const int NEED_PLUGIN = 9;
static const int NEED_LOGIN = 10;
static const int INVALID_ARGUMENT = 11;
static const int NEED_SYSTEM_PERMISSION = 12;
static const int NEED_CONFIG = 13;
static const int SERVICE_REFUSE = 14;
static const int NEED_INSTALL_APP = 15;
static const int APP_NEED_UPGRADE = 16;
static const int INITIALIZE_FAILED = 17;
static const int EMPTY_CHANNEL = 18;
static const int FUNCTION_DISABLE = 19;
static const int NEED_REALNAME = 20; // 需实名认证
static const int REALNAME_FAIL = 21; // 实名认证失败
static const int IN_PROGRESS = 22; // 上次操作尚未完成,稍后再试
static const int API_DEPRECATED = 23;
static const int LIBCURL_ERROR = 24;
static const int FREQUENCY_LIMIT = 25; //频率限制
static const int DINED_BY_APP = 26; // 被三方拒绝,需要查看具体的错误
/** 1000 ~ 1099 字段是 LOGIN 模块相关的错误码 */
static const int LOGIN_UNKNOWN_ERROR = 1000;
static const int LOGIN_NO_CACHED_DATA = 1001; // 本地没有登录缓存数据
static const int LOGIN_CACHED_DATA_EXPIRED = 1002; //本地有缓存,但是该缓存已经失效
static const int LOGIN_KEY_STORE_VERIFY_ERROR = 1004;
static const int LOGIN_NEED_USER_DATA = 1005;
static const int LOGIN_NEED_USER_DATA_SERVER = 1010;
static const int LOGIN_URL_USER_LOGIN = 1011; // 异账号使用URL登陆成功
static const int LOGIN_NEED_LOGIN = 1012; // 异账号:需要进入登陆页
static const int LOGIN_NEED_SELECT_ACCOUNT = 1013; // 异账号:需要弹出异帐号提示
static const int LOGIN_ACCOUNT_REFRESH = 1014; // 异账号通过URL将票据刷新
static const int CONNECT_NO_CACHED_DATA = 1021; // 本地没有关联渠道登录缓存数据
static const int CONNECT_CACHED_DATA_EXPIRED = 1022; //本地有缓存,但是该缓存已经失效
static const int CONNECT_NO_MATCH_MAIN_OPENID = 1023; //关联账号与主账号不一致
/** 1100 ~ 1199 字段是 FRIEND 模块相关的错误码 */
static const int FRIEND_UNKNOWN_ERROR = 1100;
/** 1200 ~ 1299 字段是 GROUP 模块相关的错误码 */
static const int GROUP_UNKNOWN_ERROR = 1200;
/** 1300 ~ 1399 字段是 NOTICE 模块相关的错误码 */
static const int NOTICE_UNKNOWN_ERROR = 1300;
/** 1400 ~ 1499 字段是 Push 模块相关的错误码 */
static const int PUSH_RECEIVER_TEXT = 1400; // 收到推送消息
static const int PUSH_NOTIFICATION_CLICK = 1401; // 在通知栏点击收到的消息
static const int PUSH_NOTIFICATION_SHOW = 1402; // 收到通知之后,通知栏显示
/** 1500 ~ 1599 字段是 WEBVIEW 模块相关的错误码 */
static const int WEBVIEW_UNKNOWN_ERROR = 1500;
static const int THIRD_ERROR = 9999;// 第三方错误情况,参考第三方错误码
};
NS_UQM_END
#endif /* UQMError_hpp */

View File

@ -0,0 +1,147 @@
//
// UQMLog.hpp
// CrashSight
//
// Created by joyfyzhang on 2020/9/3.
// Copyright © 2020 joyfyzhang. All rights reserved.
//
#ifndef UQMLog_hpp
#define UQMLog_hpp
#include <string>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "UQMMacros.h"
#include "UQMCompatLayer.h"
#include "CSLogger.h"
#if UQM_PLATFORM_WINDOWS || PLATFORM_LINUX
#else
#include <sys/cdefs.h>
#include <sys/time.h>
#include <unistd.h>
#include "zlib.h"
#endif
// 定义此宏 会在 release 日志宏中打印日志到控制台
#ifndef DEBUG
#define DEBUG
#endif
#ifndef UQM_LOG_TAG
#define UQM_LOG_TAG "[CrashSightPlugin-Native]"
#endif
#ifdef ANDROID
#define UQM_LOG_MAX_LENGTH 1023 //冗余一位,用于解决最后一个是汉字导致被截断的问题
#elif defined(__APPLE__)
#define UQM_LOG_MAX_LENGTH 4096
#endif
//#define __UQM_FILENAME1__ (strrchr(__FILE__, '/') ? (strrchr(__FILE__, '/') + 1):__FILE__)
//#define __UQM_FILENAME2__ (strrchr(__FILE__, '\\') ? (strrchr(__FILE__, '\\') + 1):__FILE__)
//#define __UQM_FILENAME__ (strrchr(__FILE__, '/') ? (__UQM_FILENAME1__):(__UQM_FILENAME2__))
//#ifdef UQM_NO_LOG_DEBUG
//#define UQM_LOG_DEBUG(...)
//#define UQM_LOG_ERROR(...)
//#define UQM_LOG_JSON(level, ...)
//#else
//#define UQM_LOG_DEBUG(...) UQMLogger(kUQMLevelDebug, UQM_LOG_TAG, __UQM_FILENAME__, __FUNCTION__, __LINE__).console().writeLog(__VA_ARGS__)
//#define UQM_LOG_ERROR(...) UQMLogger(kUQMLevelError, UQM_LOG_TAG, __UQM_FILENAME__, __FUNCTION__, __LINE__).console().writeLog(__VA_ARGS__)
//#endif
NS_UQM_BEGIN
typedef enum {
kUQMLevelDebug = 0, // 调试使用日志 精简日志kLevelVerbose、kLevelInfo、kLevelWarn 都合并成Debug
kUQMLevelError, // 错误日志
} UQMLogLevel;
typedef struct {
UQMLogLevel level;
const char *tag;
const char *fileName;
const char *funcName;
int line;
#if UQM_PLATFORM_WINDOWS || PLATFORM_LINUX
#else
struct timeval timeval;
#endif
long long pid;
long long tid;
long long mainTid;
} UQMLogInfo;
class UQM_EXPORT UQMLogger {
public:
UQMLogger(UQMLogLevel level, const char *tag, const char *fileName, const char *funcName, int line);
~UQMLogger();
// 是否打印日志到控制台
UQMLogger &console();
#if UQM_PLATFORM_WINDOWS || PLATFORM_LINUX
UQMLogger &writeLog(const char *fmt, ...);
#else
// 此接口独立出来 - 方便后续格式化
UQMLogger &writeLog(const char *fmt, ...)__attribute__((format(printf, 2, 3)));
#endif
static void consoleFormatLogVA(const UQMLogInfo *info, const char *message);
static void consoleFormatLog(const UQMLogInfo *info, const char *format);
static void consoleLog(const int level, const char *resultLog, ...);
static long long getPid() {
#if UQM_PLATFORM_WINDOWS || PLATFORM_LINUX
return -1;
#else
return getpid();
#endif
}
static long long getTid() {
#if UQM_PLATFORM_WINDOWS || PLATFORM_LINUX
return -1;
#else
#ifdef __APPLE__
return -1;
#else
return pthread_self();
#endif
#endif
}
static long long getMainTid() {
#if UQM_PLATFORM_WINDOWS || PLATFORM_LINUX
return -1;
#else
#ifdef __APPLE__
return -1;
#else
return gettid();
#endif
#endif
}
private:
UQMLogInfo info;
bool isConsole;
UQMString curLogMsg;
};
NS_UQM_END
#endif /* UQMLog_hpp */

View File

@ -0,0 +1,250 @@
//
// UQMMacroExpand.hpp
// Crashot
//
// Created by joyfyzhang on 2020/9/3.
// Copyright © 2020 joyfyzhang. All rights reserved.
//
#ifndef UQMMacroExpand_hpp
#define UQMMacroExpand_hpp
#include "UQMMacros.h"
#ifdef ANDROID
#include "jni.h"
#endif
NS_UQM_BEGIN
#ifdef ANDROID //Android 才需要 JNI 到 struct 的互转
// Java 到 struct 的代码模板
#define JNI_2_STRUCT_FUNC_BEGIN(clazzName) \
public: \
template<typename JObject> \
void jni2Struct(JObject& obj, jobject src, char const* cn = clazzName) {
#define CONVERTER_JNI_2_STRUCT_OPTIONAL(M) \
obj.convert(#M, M, src, cn);
// 设置别名
#define CONVERTER_JNI_2_STRUCT_ALIAS(M, A_NAME) CONVERTER_JNI_2_STRUCT_OPTIONAL(M)
//obj.convert(A_NAME,M, src, cn);
// call father jni2Struct add by yuanchengsu
#define CONVERTER_JNI_2_STRUCT_BASE(M) M::jni2Struct(obj,src,cn);
#define JNI_2_STRUCT_FUNC_END() }
// struct 到 JNI 的代码模板
#define STRUCT_2_JNI_FUNC_BEGIN(clazzName) \
template <class CLASS> \
void struct2JNI(CLASS& obj, const char *root, char const* cn = clazzName) const { \
#define CONVERTER_STRUCT_2_JNI_OPTIONAL(M) \
obj.convert(#M, M, cn);
#define CONVERTER_STRUCT_2_JNI_ALIAS(M, A_NAME) CONVERTER_STRUCT_2_JNI_OPTIONAL(M)
//obj.convert(A_NAME, M, cn);
//call father struct2JNI add by yuanchengsu
#define CONVERTER_STRUCT_2_JNI_BASE(M) M::struct2JNI(obj,root,cn);
#define STRUCT_2_JNI_FUNC_END() }
#endif
// json 到 struct 的代码模板
#define JSON_2_STRUCT_FUNC_BEGIN() \
public: \
template<typename Doc> \
void json2Struct(Doc& obj) {
#define CONVERTER_JSON_2_STRUCT_OPTIONAL(M) \
obj[#M].convert(M);
// 设置别名
#define CONVERTER_JSON_2_STRUCT_ALIAS(M, A_NAME) \
obj[A_NAME].convert(M);
// call father json2Struct by yuanchengsu
#define CONVERTER_JSON_2_STRUCT_BASE(M) M::json2Struct(obj);
// struct 到 json 的代码模板
#define STRUCT_2_JSON_FUNC_BEGIN() \
template <class CLASS> \
void struct2Json(CLASS& obj, const char *root) const {
#define CONVERTER_STRUCT_2_JSON_OPTIONAL(M) \
obj.convert(#M,M);
// 设置别名
#define CONVERTER_STRUCT_2_JSON_ALIAS(M, A_NAME) \
obj.convert(A_NAME,M); \
// call father struct2Json by yuanchengsu
#define CONVERTER_STRUCT_2_JSON_BASE(M) M::struct2Json(obj,root);
#define STRUCT_AND_JSON_FUNC_END() }
// 兼容层转换代码
#define RET_AND_INNER_FUNC_BEGIN() \
template <class Doc, class TypeRet> \
void innerRetConvert(Doc& doc, const TypeRet &typeRet) {
#define CONVERTER_RET_AND_INNER_OPTIONAL(M) \
doc.convert(M, typeRet.M);
// 设置别名
#define CONVERTER_RET_AND_INNER_ALIAS(M, A_NAME) CONVERTER_RET_AND_INNER_OPTIONAL(M)
//call father innerRetConvert by yuanchengsu
#define CONVERTER_RET_AND_INNER_BASE(M) M::innerRetConvert(doc,typeRet);
#define RET_AND_INNER_FUNC_END() }
#define ARG_SEQ \
_29,_28,_27,_26,_25,_24,_23,_22,_21,_20, \
_19,_18,_17,_16,_15,_14,_13,_12,_11,_10, \
_9, _8, _7, _6, _5, _4, _3, _2, _1
#define ARG_N(ACTION, \
_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
_11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
_21, _22, _23, _24, _25, _26, _27, _28, _29, NUMBER, ...) ACTION##NUMBER
#define WRAP_LEVEL_ONE(ACT, LIST, ...) ARG_N(LEVEL_ONE, __VA_ARGS__, LIST)(ACT, __VA_ARGS__)
#define WRAP_LEVEL_TWO(ACT, LIST, ...) ARG_N(LEVEL_TWO, __VA_ARGS__, LIST)(ACT, __VA_ARGS__)
#define LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_##ACT##M
#define LEVEL_ONE_1(ACT, M) LEVEL_ONE_DEF(ACT, M)
#define LEVEL_ONE_2(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_1(ACT, __VA_ARGS__)
#define LEVEL_ONE_3(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_2(ACT, __VA_ARGS__)
#define LEVEL_ONE_4(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_3(ACT, __VA_ARGS__)
#define LEVEL_ONE_5(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_4(ACT, __VA_ARGS__)
#define LEVEL_ONE_6(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_5(ACT, __VA_ARGS__)
#define LEVEL_ONE_7(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_6(ACT, __VA_ARGS__)
#define LEVEL_ONE_8(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_7(ACT, __VA_ARGS__)
#define LEVEL_ONE_9(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_8(ACT, __VA_ARGS__)
#define LEVEL_ONE_10(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_9(ACT, __VA_ARGS__)
#define LEVEL_ONE_11(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_10(ACT, __VA_ARGS__)
#define LEVEL_ONE_12(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_11(ACT, __VA_ARGS__)
#define LEVEL_ONE_13(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_12(ACT, __VA_ARGS__)
#define LEVEL_ONE_14(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_13(ACT, __VA_ARGS__)
#define LEVEL_ONE_15(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_14(ACT, __VA_ARGS__)
#define LEVEL_ONE_16(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_15(ACT, __VA_ARGS__)
#define LEVEL_ONE_17(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_16(ACT, __VA_ARGS__)
#define LEVEL_ONE_18(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_17(ACT, __VA_ARGS__)
#define LEVEL_ONE_19(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_18(ACT, __VA_ARGS__)
#define LEVEL_ONE_20(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_19(ACT, __VA_ARGS__)
#define LEVEL_ONE_21(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_20(ACT, __VA_ARGS__)
#define LEVEL_ONE_22(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_21(ACT, __VA_ARGS__)
#define LEVEL_ONE_23(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_22(ACT, __VA_ARGS__)
#define LEVEL_ONE_24(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_23(ACT, __VA_ARGS__)
#define LEVEL_ONE_25(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_24(ACT, __VA_ARGS__)
#define LEVEL_ONE_26(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_25(ACT, __VA_ARGS__)
#define LEVEL_ONE_27(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_26(ACT, __VA_ARGS__)
#define LEVEL_ONE_28(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_27(ACT, __VA_ARGS__)
#define LEVEL_ONE_29(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_28(ACT, __VA_ARGS__)
#define LEVEL_ONE_30(ACT, M, ...) LEVEL_ONE_DEF(ACT, M) LEVEL_ONE_29(ACT, __VA_ARGS__)
#define LEVEL_TWO_DEF(ACT, M) CONVERTER_##ACT(M)
#define LEVEL_TWO_1(ACT, M) LEVEL_TWO_DEF(ACT, M)
#define LEVEL_TWO_2(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_1(ACT, __VA_ARGS__)
#define LEVEL_TWO_3(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_2(ACT, __VA_ARGS__)
#define LEVEL_TWO_4(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_3(ACT, __VA_ARGS__)
#define LEVEL_TWO_5(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_4(ACT, __VA_ARGS__)
#define LEVEL_TWO_6(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_5(ACT, __VA_ARGS__)
#define LEVEL_TWO_7(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_6(ACT, __VA_ARGS__)
#define LEVEL_TWO_8(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_7(ACT, __VA_ARGS__)
#define LEVEL_TWO_9(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_8(ACT, __VA_ARGS__)
#define LEVEL_TWO_10(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_9(ACT, __VA_ARGS__)
#define LEVEL_TWO_11(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_10(ACT, __VA_ARGS__)
#define LEVEL_TWO_12(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_11(ACT, __VA_ARGS__)
#define LEVEL_TWO_13(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_12(ACT, __VA_ARGS__)
#define LEVEL_TWO_14(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_13(ACT, __VA_ARGS__)
#define LEVEL_TWO_15(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_14(ACT, __VA_ARGS__)
#define LEVEL_TWO_16(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_15(ACT, __VA_ARGS__)
#define LEVEL_TWO_17(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_16(ACT, __VA_ARGS__)
#define LEVEL_TWO_18(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_17(ACT, __VA_ARGS__)
#define LEVEL_TWO_19(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_18(ACT, __VA_ARGS__)
#define LEVEL_TWO_20(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_19(ACT, __VA_ARGS__)
#define LEVEL_TWO_21(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_20(ACT, __VA_ARGS__)
#define LEVEL_TWO_22(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_21(ACT, __VA_ARGS__)
#define LEVEL_TWO_23(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_22(ACT, __VA_ARGS__)
#define LEVEL_TWO_24(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_23(ACT, __VA_ARGS__)
#define LEVEL_TWO_25(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_24(ACT, __VA_ARGS__)
#define LEVEL_TWO_26(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_25(ACT, __VA_ARGS__)
#define LEVEL_TWO_27(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_26(ACT, __VA_ARGS__)
#define LEVEL_TWO_28(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_27(ACT, __VA_ARGS__)
#define LEVEL_TWO_29(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_28(ACT, __VA_ARGS__)
#define LEVEL_TWO_30(ACT, M, ...) LEVEL_TWO_DEF(ACT, M) LEVEL_TWO_29(ACT, __VA_ARGS__)
// struct to string
#define LEVEL_ONE_STRUCT_2_JNI_O(...) WRAP_LEVEL_TWO(STRUCT_2_JNI_OPTIONAL, ARG_SEQ, __VA_ARGS__)
#define LEVEL_ONE_STRUCT_2_JNI_A(M, A) CONVERTER_STRUCT_2_JNI_ALIAS(M,A)
#define LEVEL_ONE_STRUCT_2_JSON_O(...) WRAP_LEVEL_TWO(STRUCT_2_JSON_OPTIONAL, ARG_SEQ, __VA_ARGS__)
#define LEVEL_ONE_STRUCT_2_JSON_A(M, A) CONVERTER_STRUCT_2_JSON_ALIAS(M,A)
#define LEVEL_ONE_RET_AND_INNER_O(...) WRAP_LEVEL_TWO(RET_AND_INNER_OPTIONAL, ARG_SEQ, __VA_ARGS__)
#define LEVEL_ONE_RET_AND_INNER_A(M, A) CONVERTER_RET_AND_INNER_ALIAS(M,A)
// string to struct
#define LEVEL_ONE_JNI_2_STRUCT_O(...) WRAP_LEVEL_TWO(JNI_2_STRUCT_OPTIONAL, ARG_SEQ, __VA_ARGS__)
#define LEVEL_ONE_JNI_2_STRUCT_A(M, A) CONVERTER_JNI_2_STRUCT_ALIAS(M,A)
#define LEVEL_ONE_JSON_2_STRUCT_O(...) WRAP_LEVEL_TWO(JSON_2_STRUCT_OPTIONAL, ARG_SEQ, __VA_ARGS__)
#define LEVEL_ONE_JSON_2_STRUCT_A(M, A) CONVERTER_JSON_2_STRUCT_ALIAS(M,A)
// fix inherit by yuanchengsu
#define LEVEL_ONE_STRUCT_2_JSON_B(...) WRAP_LEVEL_TWO(STRUCT_2_JSON_BASE, ARG_SEQ, __VA_ARGS__)
#define LEVEL_ONE_RET_AND_INNER_B(...) WRAP_LEVEL_TWO(RET_AND_INNER_BASE, ARG_SEQ, __VA_ARGS__)
#define LEVEL_ONE_JSON_2_STRUCT_B(...) WRAP_LEVEL_TWO(JSON_2_STRUCT_BASE, ARG_SEQ, __VA_ARGS__)
#define LEVEL_ONE_JNI_2_STRUCT_B(...) WRAP_LEVEL_TWO(JNI_2_STRUCT_BASE, ARG_SEQ, __VA_ARGS__)
#define LEVEL_ONE_STRUCT_2_JNI_B(...) WRAP_LEVEL_TWO(STRUCT_2_JNI_BASE, ARG_SEQ, __VA_ARGS__)
#ifdef ANDROID
#define UQM_AutoParser(clazzName, ...) \
JNI_2_STRUCT_FUNC_BEGIN(clazzName) \
WRAP_LEVEL_ONE(JNI_2_STRUCT_, ARG_SEQ, __VA_ARGS__) \
JNI_2_STRUCT_FUNC_END() \
\
STRUCT_2_JNI_FUNC_BEGIN(clazzName) \
WRAP_LEVEL_ONE(STRUCT_2_JNI_, ARG_SEQ, __VA_ARGS__) \
STRUCT_2_JNI_FUNC_END() \
\
JSON_2_STRUCT_FUNC_BEGIN() \
WRAP_LEVEL_ONE(JSON_2_STRUCT_, ARG_SEQ, __VA_ARGS__) \
STRUCT_AND_JSON_FUNC_END() \
\
STRUCT_2_JSON_FUNC_BEGIN() \
WRAP_LEVEL_ONE(STRUCT_2_JSON_, ARG_SEQ, __VA_ARGS__) \
STRUCT_AND_JSON_FUNC_END() \
\
RET_AND_INNER_FUNC_BEGIN() \
WRAP_LEVEL_ONE(RET_AND_INNER_, ARG_SEQ, __VA_ARGS__) \
RET_AND_INNER_FUNC_END()
#else
#define UQM_AutoParser(clazzName, ...) \
JSON_2_STRUCT_FUNC_BEGIN() \
WRAP_LEVEL_ONE(JSON_2_STRUCT_, ARG_SEQ, __VA_ARGS__) \
STRUCT_AND_JSON_FUNC_END() \
\
STRUCT_2_JSON_FUNC_BEGIN() \
WRAP_LEVEL_ONE(STRUCT_2_JSON_, ARG_SEQ, __VA_ARGS__) \
STRUCT_AND_JSON_FUNC_END() \
\
RET_AND_INNER_FUNC_BEGIN() \
WRAP_LEVEL_ONE(RET_AND_INNER_, ARG_SEQ, __VA_ARGS__) \
RET_AND_INNER_FUNC_END()
#endif
NS_UQM_END
#endif /* UQMMacroExpand_hpp */

View File

@ -0,0 +1,171 @@
//
// UQMMacros.hpp
// UQM
//
// Created by joyfyzhang on 2020/9/3.
// Copyright © 2020 joyfyzhang. All rights reserved.
//
#ifndef UQMMacros_hpp
#define UQMMacros_hpp
#include <set>
#include <map>
#include <list>
#include <string>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <cwchar>
#include <iostream>
#ifdef __cplusplus
#define NS_UQM_BEGIN namespace UQM \
{
#define NS_UQM_END }
#define USING_NS_UQM using namespace UQM;
#else
#define NS_UQM_BEGIN
#define NS_UQM_END
#define USING_NS_UQM
#endif
#define UQM_UUID_KEY_NAME "uqm_uuid"
#define UQM_CONFIG_DEFAULT_GAME_ID "11"
#define UQM_SEQ_ID_PRIMARY_KEY_NAME "uqm_seq_id_primary_key"
//适配 UE4 以及 Cocos 系统定义
#if PLATFORM_WINDOWS
#undef UQM_PLATFORM_WINDOWS
#define UQM_PLATFORM_WINDOWS 1
#else
#if defined(_WIN32) || defined(_WIN64)
#undef UQM_PLATFORM_WINDOWS
#define UQM_PLATFORM_WINDOWS 1
#elif defined(__APPLE__)
#include <TargetConditionals.h>
#undef UQM_PLATFORM_WINDOWS
#define UQM_PLATFORM_WINDOWS 0
#if TARGET_OS_IOS || TARGET_OS_IPHONE
#undef UQM_PLATFORM_MAC
#define UQM_PLATFORM_MAC 0
#else
#undef UQM_PLATFORM_MAC
#define UQM_PLATFORM_MAC 1
#endif
#else
#undef UQM_PLATFORM_WINDOWS
#define UQM_PLATFORM_WINDOWS 0
#undef UQM_PLATFORM_MAC
#define UQM_PLATFORM_MAC 0
#endif
#endif
//UE4 环境
#if PLATFORM_WINDOWS || PLATFORM_MAC || PLATFORM_IOS || PLATFORM_ANDROID
#undef UQM_UE4
#define UQM_UE4 1
#endif
////UE4 windows 游客登录需要做dll 函数导出的特殊处理
#if UQM_PLATFORM_WINDOWS
#ifdef UQM_CORE
#define UQM_EXPORT_UE __declspec(dllexport)
#else
#define UQM_EXPORT_UE __declspec(dllimport)
#endif
#define UQM_EXPORT
#define UQM_HIDDEN
#else
#define UQM_EXPORT_UE
#if __GNUC__ >= 4
#if defined(__APPLE__)
#ifdef UQM_UE4
// #define UQM_EXPORT UQMCORE_API
// #define UQM_HIDDEN UQMCORE_API
#define UQM_EXPORT
#define UQM_HIDDEN
#else
#define UQM_EXPORT
#define UQM_HIDDEN
#endif
#elif defined(CRASHSIGHT_PS4) || defined(CRASHSIGHT_PS5)
#define UQM_EXPORT __declspec(dllimport)
#define UQM_HIDDEN
#else
#define UQM_EXPORT __attribute__ ((visibility ("default")))
#define UQM_HIDDEN __attribute__ ((visibility ("hidden")))
#endif
#else
#define UQM_EXPORT
#define UQM_HIDDEN
#endif
#endif
//UE4 Mac/Windows
#if UQM_PLATFORM_WINDOWS
#else
#ifdef ANDROID
#define UQM_VERSION "5.4.000.5057"
#define UQM_CUR_OS 1
#elif defined(__APPLE__)
#define UQM_CUR_OS 2
#define UQM_VERSION "5.4.000.5057"
#endif
#endif
#if UQM_PLATFORM_WINDOWS
#else
#ifdef __APPLE__
#define UQM_LABEL_KEYCHAIN_ENABLE "UQM_KEYCHAIN_ENABLE"
#endif
#endif
// 删除单个指针和删除多个指针
#define UQM_SAFE_DELETE(ptr) \
do \
{ \
if (ptr != NULL) \
{ \
delete ptr; \
ptr = NULL; \
} \
} while (0)
#define UQM_SAFE_DELETE_ARR(ptr) \
do \
{ \
if (ptr != NULL) \
{ \
delete[] ptr; \
ptr = NULL; \
} \
} while (0)
// 分配内存和释放内存
#define UQM_SAFE_MALLOC(num, type) (type *) calloc((num) , sizeof(type))
#define UQM_SAFE_FREE(ptr) \
do \
{ \
if (ptr != NULL) \
{ \
free(ptr); \
ptr = NULL; \
} \
} while (0)
#if defined(__has_cpp_attribute)
# if __has_cpp_attribute(deprecated)
# define CS_DEPRECATED(msg) [[deprecated(msg)]]
# else
# define CS_DEPRECATED(msg)
# endif
#else
# define CS_DEPRECATED(msg)
#endif
#endif /* UQMMacros_hpp */

View File

@ -0,0 +1,13 @@
//
// UQMRename.h
// Crashot
//
// Created by joyfyzhang on 2020/9/3.
// Copyright © 2020 joyfyzhang. All rights reserved.
//
#ifndef UQMRename_h
#define UQMRename_h
#endif /* UQMRename_h */

View File

@ -0,0 +1,66 @@
//
// UQMSingleton.hpp
// Crashot
//
// Created by joyfyzhang on 2020/9/3.
// Copyright © 2020 joyfyzhang. All rights reserved.
//
#ifndef UQMSingleton_hpp
#define UQMSingleton_hpp
#include <stdio.h>
#include "UQMMacros.h"
template<class T>
class UQMSingleton
{
protected:
UQMSingleton() {};
private:
UQMSingleton(const UQMSingleton &) {};
UQMSingleton &operator=(const UQMSingleton &) {};
static T *mInstance;
#if UQM_PLATFORM_WINDOWS
#else
static pthread_mutex_t mMutex;
#endif
public:
static T *GetInstance();
};
template<class T>
T *UQMSingleton<T>::GetInstance()
{
if (mInstance == NULL)
{
#if UQM_PLATFORM_WINDOWS
#else
pthread_mutex_lock(&mMutex);
#endif
if (mInstance == NULL)
{
T *tmp = new T();
mInstance = tmp;
}
#if UQM_PLATFORM_WINDOWS
#else
pthread_mutex_unlock(&mMutex);
#endif
}
return mInstance;
}
#if UQM_PLATFORM_WINDOWS
#else
template<class T>
pthread_mutex_t UQMSingleton<T>::mMutex = PTHREAD_MUTEX_INITIALIZER;
#endif
template<class T>
T *UQMSingleton<T>::mInstance = NULL;
#endif /* UQMSingleton_hpp */

View File

@ -0,0 +1,142 @@
//
// UQMSynthesizeSingleton.h
// UQMCore
//
// Created by Hillson Song on 5/14/18.
// Copyright © 2018. All rights reserved.
//
#ifndef SYNTHESIZE_SINGLETON_FOR_CLASS_H
#define SYNTHESIZE_SINGLETON_FOR_CLASS_H
#import <objc/runtime.h>
#pragma mark -
#pragma mark Singleton
/* Synthesize Singleton For Class
*
* Creates a singleton interface for the specified class with the following methods:
*
* + (MyClass*) sharedInstance;
* + (void) purgeSharedInstance;
*
* Calling sharedInstance will instantiate the class and swizzle some methods to ensure
* that only a single instance ever exists.
* Calling purgeSharedInstance will destroy the shared instance and return the swizzled
* methods to their former selves.
*
*
* Usage:
*
* MyClass.h:
* ========================================
* #import "SynthesizeSingleton.h"
*
* @interface MyClass: SomeSuperclass
* {
* ...
* }
* SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER(MyClass);
*
* @end
* ========================================
*
*
* MyClass.m:
* ========================================
* #import "MyClass.h"
*
* @implementation MyClass
*
* SYNTHESIZE_SINGLETON_FOR_CLASS(MyClass);
*
* ...
*
* @end
* ========================================
*
*
* Note: Calling alloc manually will also initialize the singleton, so you
* can call a more complex init routine to initialize the singleton like so:
*
* [[MyClass alloc] initWithParam:firstParam secondParam:secondParam];
*
* Just be sure to make such a call BEFORE you call "sharedInstance" in
* your program.
*/
#define SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER(__CLASSNAME__) \
\
+ (__CLASSNAME__*) sharedInstance; \
+ (void) purgeSharedInstance;
#define SYNTHESIZE_SINGLETON_FOR_CLASS(__CLASSNAME__) \
\
static __CLASSNAME__* volatile _##__CLASSNAME__##_sharedInstance = nil; \
\
+ (__CLASSNAME__*) sharedInstanceNoSynch \
{ \
return (__CLASSNAME__*) _##__CLASSNAME__##_sharedInstance; \
} \
\
+ (__CLASSNAME__*) sharedInstanceSynch \
{ \
@synchronized(self) \
{ \
if(nil == _##__CLASSNAME__##_sharedInstance) \
{ \
_##__CLASSNAME__##_sharedInstance = [[self alloc] init]; \
} \
else \
{ \
NSAssert2(1==0, @"SynthesizeSingleton: %@ ERROR: +(%@ *)sharedInstance method did not get swizzled.", self, self); \
} \
} \
return (__CLASSNAME__*) _##__CLASSNAME__##_sharedInstance; \
} \
\
+ (__CLASSNAME__*) sharedInstance \
{ \
return [self sharedInstanceSynch]; \
} \
\
+ (id)allocWithZone:(NSZone*) zone \
{ \
@synchronized(self) \
{ \
if (nil == _##__CLASSNAME__##_sharedInstance) \
{ \
_##__CLASSNAME__##_sharedInstance = [super allocWithZone:zone]; \
if(nil != _##__CLASSNAME__##_sharedInstance) \
{ \
Method newSharedInstanceMethod = class_getClassMethod(self, @selector(sharedInstanceNoSynch)); \
method_setImplementation(class_getClassMethod(self, @selector(sharedInstance)), method_getImplementation(newSharedInstanceMethod)); \
} \
} \
} \
return _##__CLASSNAME__##_sharedInstance; \
} \
\
+ (void)purgeSharedInstance \
{ \
@synchronized(self) \
{ \
if(nil != _##__CLASSNAME__##_sharedInstance) \
{ \
Method newSharedInstanceMethod = class_getClassMethod(self, @selector(sharedInstanceSynch)); \
method_setImplementation(class_getClassMethod(self, @selector(sharedInstance)), method_getImplementation(newSharedInstanceMethod)); \
_##__CLASSNAME__##_sharedInstance = nil; \
} \
} \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
return self; \
} \
\
#endif

View File

@ -0,0 +1,43 @@
/*!
* @header UQMThread.h
* @Version 2.0.0
* @date 2018/4/25
* @abstract
* thread
*
* @copyright
* Copyright © 2018. All rights reserved.
*/
#ifndef UQM_THREAD_H
#define UQM_THREAD_H
#include <sstream>
#include "UQMLog.h"
#include "UQMMacros.h"
NS_UQM_BEGIN
/*
* 线
* @param module
* 使iOS线
*/
bool thread_set_msdk_name(const std::string &module);
#ifdef ANDROID
/*
* 线
* @return 线
*/
std::string thread_self_get_name();
/*
* 线
*/
bool thread_self_set_name(const std::string &name);
#endif
NS_UQM_END
#endif //UQM_THREAD_H

View File

@ -0,0 +1,29 @@
//
// UQMUtils.hpp
// Crashot
//(内部使用)简单的工具类声明,目前包含:
// 1. 生成通用唯一识别码
// 2. 格式化输出 Json 字符串
// 3. 字符串跟数字连接工具
// 4. 类型转换工具,将一个类型的值 <InType> 转换为另一个类型 <OutType>
// Created by joyfyzhang on 2020/9/3.
// Copyright © 2020 joyfyzhang. All rights reserved.
//
#ifndef UQMUtils_hpp
#define UQMUtils_hpp
#include "UQMDefine.h"
NS_UQM_BEGIN
class UQM_EXPORT UQMUtils
{
public:
// 移除空格
static const char *Trim(const char *name);
};
NS_UQM_END
#endif /* UQMUtils_hpp */

View File

@ -0,0 +1,50 @@
//
// UQMUtilsIOS.h
// Crashot
//
// Created by joyfyzhang on 2020/9/4.
// Copyright © 2020 joyfyzhang. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "UQMDefine.h"
#define GET_NSSTRING(cString) [NSString stringWithCString:(cString.c_str()?cString:"").c_str() encoding:NSUTF8StringEncoding]
@interface UQMUtilsIOS : NSObject
/**
* NSDictionaryJSON
*
* @param dict
* @param prettyPrint JSON使
*
* @return JSON
*/
+ (NSString *)jsonStringFromDict:(NSDictionary *)dict prettyPrint:(BOOL)prettyPrint;
/**
* KVPair vector => NSDictionary
*
* @param kvVector KVPair vector
*
* @return
*/
+ (NSDictionary *)dictFromKVVector:(UQM::UQMVector<UQM::UQMKVPair>)kvVector;
/**
* c++ map => NSDictionary
*
* @param kvMap std::map<std::string,std::string>
*
* @return
*/
+ (NSDictionary *)dictFromKVMap:(std::map<std::string,std::string> &)kvMap;
///**
// * 获取原始设备型号
// *
// * @return 设备型号
// */
//+ (NSString *)getCurrentDeviceModel;
@end

View File

@ -0,0 +1,149 @@
/*
Copyright (c) 2009 Dave Gamble
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef cJSON__h
#define cJSON__h
#include "UQMMacros.h"
NS_UQM_BEGIN
#ifdef __cplusplus
extern "C"
{
#endif
/* cJSON Types: */
#define cJSON_False 0
#define cJSON_True 1
#define cJSON_NULL 2
#define cJSON_Number 3
#define cJSON_String 4
#define cJSON_Array 5
#define cJSON_Object 6
#define cJSON_IsReference 256
/* The cJSON structure: */
typedef struct cJSON {
struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
int type; /* The type of the item, as above. */
char *valuestring; /* The item's string, if type==cJSON_String */
int valueint; /* The item's number, if type==cJSON_Number */
double valuedouble; /* The item's number, if type==cJSON_Number */
char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
} cJSON;
typedef struct cJSON_Hooks {
void *(*malloc_fn)(size_t sz);
void (*free_fn)(void *ptr);
} cJSON_Hooks;
/* Supply malloc, realloc and free functions to cJSON */
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
extern cJSON *cJSON_Parse(const char *value);
/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
extern char * UQM_EXPORT cJSON_Print(cJSON *item);
/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
extern char *cJSON_PrintUnformatted(cJSON *item);
/* Delete a cJSON entity and all subentities. */
extern void UQM_EXPORT cJSON_Delete(cJSON *c);
/* Returns the number of items in an array (or object). */
extern int cJSON_GetArraySize(cJSON *array);
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
/* Get item "string" from object. Case insensitive. */
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
extern const char *cJSON_GetErrorPtr(void);
/* These calls create a cJSON item of the appropriate type. */
extern cJSON * UQM_EXPORT cJSON_CreateNull(void);
extern cJSON * UQM_EXPORT cJSON_CreateTrue(void);
extern cJSON * UQM_EXPORT cJSON_CreateFalse(void);
extern cJSON * UQM_EXPORT cJSON_CreateBool(int b);
extern cJSON * UQM_EXPORT cJSON_CreateNumber(double num);
extern cJSON * UQM_EXPORT cJSON_CreateString(const char *string);
extern cJSON * UQM_EXPORT cJSON_CreateArray(void);
extern cJSON * UQM_EXPORT cJSON_CreateObject(void);
/* These utilities create an Array of count items. */
extern cJSON *cJSON_CreateIntArray(const int *numbers,int count);
extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count);
extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count);
extern cJSON * UQM_EXPORT cJSON_CreateStringArray(const char **strings,int count);
/* Append item to the specified array/object. */
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
extern void UQM_EXPORT cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
/* Remove/Detatch items from Arrays/Objects. */
extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
extern void cJSON_DeleteItemFromArray(cJSON *array,int which);
extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);
/* Update array items. */
extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
/* Duplicate a cJSON item */
extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
need to be released. With recurse!=0, it will duplicate any children connected to the item.
The item->next and ->prev pointers are always zero on return from Duplicate. */
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);
extern void cJSON_Minify(char *json);
/* Macros for creating things quickly. */
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
#ifdef __cplusplus
}
#endif
NS_UQM_END
#endif

View File

@ -0,0 +1,6 @@
framework module CrashSightCore {
umbrella header "CrashSightCore.h"
export *
module * { export * }
}

View File

@ -0,0 +1,106 @@
fileFormatVersion: 2
guid: 4c6e924cfb5704911aeed9d27fd6722e
folderAsset: yes
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
'': Any
second:
enabled: 0
settings:
Exclude Android: 1
Exclude Editor: 1
Exclude Linux: 1
Exclude Linux64: 1
Exclude LinuxUniversal: 1
Exclude OSXUniversal: 1
Exclude Win: 1
Exclude Win64: 1
Exclude iOS: 0
- first:
Android: Android
second:
enabled: 0
settings:
CPU: ARMv7
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
CPU: AnyCPU
DefaultValueInitialized: true
OS: AnyOS
- first:
Facebook: Win
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Facebook: Win64
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Standalone: Linux
second:
enabled: 0
settings:
CPU: x86
- first:
Standalone: Linux64
second:
enabled: 0
settings:
CPU: x86_64
- first:
Standalone: LinuxUniversal
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: OSXUniversal
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Standalone: Win
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Standalone: Win64
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
iPhone: iOS
second:
enabled: 1
settings:
AddToEmbeddedBinaries: true
CompileFlags:
FrameworkDependencies: Security;
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,28 @@
//
// CrashSight.h
//
// Created by joyfyzhang on 2021/1/8.
// Copyright © 2021 joyfyzhang. All rights reserved.
//
#ifndef CrashSight_h
#define CrashSight_h
#import <Foundation/Foundation.h>
#import <CrashSightCore/CrashSightCore.h>
/**
*
* - UQMCrash +
* - UQMCrashDelegate
*/
@interface CrashSightPlugin : NSObject <UQMCrashDelegate>
/** 插件必须是的单例的,建议使用 UQM 提供的宏定义进行处理
* -
*/
SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER(CrashSightPlugin)
@end
#endif /* CrashSight_h */

View File

@ -0,0 +1,6 @@
framework module CrashSightPlugin {
umbrella header "CrashSightPlugin.h"
export *
module * { export * }
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 34047571c56b3c94f92a828719fbabce
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 81a06a3bb7606664d93044a9c50eb28e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bca1e29d2ac885d428e49570f70a71c0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,63 @@
using UnityEngine;
namespace GCloud.UQM
{
#region UQM
/// <summary>
/// 回调的范型
/// </summary>
public delegate void OnUQMRetEventHandler<T> (T ret);
public delegate string OnUQMStringRetEventHandler<T> (T ret, T crashType);
public delegate string OnUQMStringRetSetLogPathEventHandler<T>(T ret, T crashType);
public delegate void OnUQMRetLogUploadEventHandler<T>(T ret, T crashType, T result);
public class UQM
{
#if UNITY_ANDROID
public const string LibName = "CrashSight";
#elif UNITY_IOS
public const string LibName = "__Internal";
#elif UNITY_STANDALONE_WIN
#if UNITY_64//win64
public const string LibName = "CrashSight64";
#else//win32
public const string LibName = "CrashSight";
#endif
#elif UNITY_STANDALONE_OSX
public const string LibName = "CrashSight";
#elif UNITY_XBOXONE
public const string LibName = "CrashSightXbox";
#elif UNITY_PS4 || UNITY_PS5
public const string LibName = "libcs";
#elif UNITY_SWITCH
public const string LibName = "__Internal";
#elif UNITY_STANDALONE_LINUX
public const string LibName = "CrashSight";
#elif UNITY_OPENHARMONY
public const string LibName = "CrashSight";
#else
public const string LibName = "__Internal";
#endif
private static bool initialized;
public static bool isDebug = true;
/// <summary>
/// UQM init游戏开始的时候设置
/// </summary>
public static void Init()
{
if (initialized) return;
initialized = true;
if (isDebug)
UQMLog.SetLevel(UQMLog.Level.Log);
else
UQMLog.SetLevel(UQMLog.Level.Error);
UQMLog.Log ("UQM initialed !");
}
}
#endregion
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 28b1e81b8fa4086468b902ed1d439949
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 23cacf0f55b6da543b1acb95f0e14ed3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b52276a529d7da24182db01f818363b1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,10 @@
namespace GCloud.UQM
{
public enum UQMMethodNameID
{
UQM_CRASH_CALLBACK_EXTRA_DATA = 1011,
UQM_CRASH_CALLBACK_EXTRA_MESSAGE = 1012,
UQM_CRASH_CALLBACK_SET_LOG_PATH = 1013,
UQM_CRASH_CALLBACK_LOG_UPLOAD_RESULT = 1014
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 831d916e1a2a1e24abc60bb7258090ea
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,87 @@
using System;
namespace GCloud.UQM
{
/// <summary>
/// UQM log
/// </summary>
class UQMLog
{
/// <summary>
/// UQM SDK Log level
/// </summary>
public enum Level
{
None = 0,
Log,
Warning,
Error
}
/// <summary>
/// The level, Error by default
/// </summary>
private static Level level = Level.Error;
private const string header = "[CrashSightPlugin-Unity]";
/// <summary>
/// Sets the level.
/// </summary>
/// <param name="l">Level</param>
public static void SetLevel (Level l)
{
level = l;
}
/// <summary>
/// Log the specified message.
/// </summary>
/// <param name="message">Message.</param>
public static void Log (string message)
{
if (level <= Level.Log) {
UnityEngine.Debug.Log (header + message);
}
}
/// <summary>
/// Warning the specified message.
/// </summary>
/// <param name="message">Message.</param>
public static void LogWarning (string message)
{
if (level <= Level.Warning) {
UnityEngine.Debug.LogWarning (header + message);
}
}
/// <summary>
/// Error the specified message.
/// </summary>
/// <param name="message">Message.</param>
public static void LogError (string message)
{
if (level <= Level.Error) {
UnityEngine.Debug.LogError (header + message);
}
}
public static void FullLog (string message)
{
try {
var counter = 0;
const int step = 512;
var all = message.Length;
while (counter < all) {
var start = counter;
var length = start + step > all ? all - start : step;
//UnityEngine.Debug.LogError(header + "all : " + all + " start : " + start + " length : " + length);
UnityEngine.Debug.Log (header + message.Substring (start, length));
counter += step;
}
} catch (Exception e) {
UnityEngine.Debug.LogWarning (e.Message);
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2dacb082ac621aa4c9f4eedad0e683b7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,140 @@
using AOT;
using System.Runtime.InteropServices;
using System.Threading;
using UnityEngine;
namespace GCloud.UQM
{
public class RetArgsWrapper
{
private readonly int methodId;
private readonly int crashType;
private readonly int logUploadResult;
public int MethodId
{
get { return methodId; }
}
public int CrashType
{
get { return crashType; }
}
public int LogUploadResult
{
get { return logUploadResult; }
}
public RetArgsWrapper(int _methodId, int _crashType, int _logUploadResult)
{
methodId = _methodId;
crashType = _crashType;
logUploadResult = _logUploadResult;
}
}
#region UQMMessageCenter
public class UQMMessageCenter : MonoBehaviour
{
#region json ret and callback
private static bool initialzed = false;
private delegate string UQMRetJsonEventHandler(int methodId, int callType, int logUploadResult);
[MonoPInvokeCallback(typeof(UQMRetJsonEventHandler))]
public static string OnUQMRet(int methodId, int crashType, int logUploadResult)
{
var argsWrapper = new RetArgsWrapper(methodId, crashType, logUploadResult);
UQMLog.Log("OnUQMRet, the methodId is ( " + methodId + " ) crashType=" + crashType);
if (methodId == (int)UQMMethodNameID.UQM_CRASH_CALLBACK_EXTRA_MESSAGE
|| methodId == (int)UQMMethodNameID.UQM_CRASH_CALLBACK_EXTRA_DATA
|| methodId == (int)UQMMethodNameID.UQM_CRASH_CALLBACK_SET_LOG_PATH
|| methodId == (int)UQMMethodNameID.UQM_CRASH_CALLBACK_LOG_UPLOAD_RESULT
)
{
lock (CrashSightAgent.callbackThreadsLock) {
CrashSightAgent.callbackThreads.Add(Thread.CurrentThread.ManagedThreadId);
}
string result = SynchronousDelegate(argsWrapper);
lock (CrashSightAgent.callbackThreadsLock) {
CrashSightAgent.callbackThreads.Remove(Thread.CurrentThread.ManagedThreadId);
}
return result;
}
return "";
}
#if (UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_OPENHARMONY || UNITY_STANDALONE_LINUX) && !UNITY_EDITOR
[DllImport(UQM.LibName, CallingConvention = CallingConvention.Cdecl)]
private static extern void cs_setUnityCallback(UQMRetJsonEventHandler eventHandler);
#endif
#endregion
static UQMMessageCenter instance;
public static UQMMessageCenter Instance
{
get
{
if (instance != null) return instance;
var bridgeGameObject = new GameObject { name = "UQMMessageCenter" };
DontDestroyOnLoad(bridgeGameObject);
instance = bridgeGameObject.AddComponent(typeof(UQMMessageCenter)) as UQMMessageCenter;
UQMLog.Log("UQMMessageCenter instance=" + instance);
return instance;
}
}
public void Init()
{
#if (UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_OPENHARMONY || UNITY_STANDALONE_LINUX) && !UNITY_EDITOR
if (initialzed) {
return;
}
cs_setUnityCallback(OnUQMRet);
initialzed = true;
#endif
UQMLog.Log("UQM Init, set unity callback");
}
public void Uninit()
{
#if (UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_OPENHARMONY || UNITY_STANDALONE_LINUX) && !UNITY_EDITOR
cs_setUnityCallback(null);
#endif
UQMLog.Log("UQM Uninit, set unity callback to null");
}
static string SynchronousDelegate(object arg)
{
var argsWrapper = (RetArgsWrapper)arg;
var methodId = argsWrapper.MethodId;
var crashType = argsWrapper.CrashType;
UQMLog.Log("the methodId is ( " + methodId + " ) and crashType=" + crashType);
switch (methodId)
{
#if UNITY_WSA
#else
case (int)UQMMethodNameID.UQM_CRASH_CALLBACK_EXTRA_MESSAGE:
return UQMCrash.OnCrashCallbackMessage(methodId, crashType);
case (int)UQMMethodNameID.UQM_CRASH_CALLBACK_EXTRA_DATA:
return UQMCrash.OnCrashCallbackData(methodId, crashType);
case (int)UQMMethodNameID.UQM_CRASH_CALLBACK_SET_LOG_PATH:
return UQMCrash.OnCrashSetLogPathMessage(methodId, crashType);
case (int)UQMMethodNameID.UQM_CRASH_CALLBACK_LOG_UPLOAD_RESULT:
return UQMCrash.OnCrashLogUploadMessage(methodId, crashType, argsWrapper.LogUploadResult);
#endif
}
return "";
}
#endregion
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 524f6583d96f8ef4ca16ac5cf1e72745
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,516 @@
/*
* Copyright (c) 2013 Calvin Rien
*
* Based on the JSON parser by Patrick van Bergen
* http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html
*
* Simplified it so that it doesn't throw exceptions
* and can be used in Unity iOS with maximum code stripping.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace GCloud.UQM.MiniJSON
{
/// <summary>
/// This class encodes and decodes JSON strings.
/// Spec. details, see http://www.json.org/
///
/// JSON uses Arrays and Objects. These correspond here to the datatypes IList and IDictionary.
/// All numbers are parsed to doubles.
/// </summary>
public static class Json {
/// <summary>
/// Parses the string json into a value
/// </summary>
/// <param name="json">A JSON string.</param>
/// <returns>An List&lt;object&gt;, a Dictionary&lt;string, object&gt;, a double, an integer,a string, null, true, or false</returns>
public static object Deserialize(string json) {
// save the string for debug information
if (json == null) {
return null;
}
return Parser.Parse(json);
}
sealed class Parser : IDisposable {
const string WORD_BREAK = "{}[],:\"";
public static bool IsWordBreak(char c) {
return Char.IsWhiteSpace(c) || WORD_BREAK.IndexOf(c) != -1;
}
enum TOKEN {
NONE,
CURLY_OPEN,
CURLY_CLOSE,
SQUARED_OPEN,
SQUARED_CLOSE,
COLON,
COMMA,
STRING,
NUMBER,
TRUE,
FALSE,
NULL
};
StringReader json;
Parser(string jsonString) {
json = new StringReader(jsonString);
}
public static object Parse(string jsonString) {
using (var instance = new Parser(jsonString)) {
return instance.ParseValue();
}
}
public void Dispose() {
json.Dispose();
json = null;
}
Dictionary<string, object> ParseObject() {
Dictionary<string, object> table = new Dictionary<string, object>();
// ditch opening brace
json.Read();
// {
while (true) {
switch (NextToken) {
case TOKEN.NONE:
return null;
case TOKEN.COMMA:
continue;
case TOKEN.CURLY_CLOSE:
return table;
default:
// name
string name = ParseString();
if (name == null) {
return null;
}
// :
if (NextToken != TOKEN.COLON) {
return null;
}
// ditch the colon
json.Read();
// value
table[name] = ParseValue();
break;
}
}
}
List<object> ParseArray() {
List<object> array = new List<object>();
// ditch opening bracket
json.Read();
// [
var parsing = true;
while (parsing) {
TOKEN nextToken = NextToken;
switch (nextToken) {
case TOKEN.NONE:
return null;
case TOKEN.COMMA:
continue;
case TOKEN.SQUARED_CLOSE:
parsing = false;
break;
default:
object value = ParseByToken(nextToken);
array.Add(value);
break;
}
}
return array;
}
object ParseValue() {
TOKEN nextToken = NextToken;
return ParseByToken(nextToken);
}
object ParseByToken(TOKEN token) {
switch (token) {
case TOKEN.STRING:
return ParseString();
case TOKEN.NUMBER:
return ParseNumber();
case TOKEN.CURLY_OPEN:
return ParseObject();
case TOKEN.SQUARED_OPEN:
return ParseArray();
case TOKEN.TRUE:
return true;
case TOKEN.FALSE:
return false;
case TOKEN.NULL:
return null;
default:
return null;
}
}
string ParseString() {
StringBuilder s = new StringBuilder();
char c;
// ditch opening quote
json.Read();
bool parsing = true;
while (parsing) {
if (json.Peek() == -1) {
parsing = false;
break;
}
c = NextChar;
switch (c) {
case '"':
parsing = false;
break;
case '\\':
if (json.Peek() == -1) {
parsing = false;
break;
}
c = NextChar;
switch (c) {
case '"':
case '\\':
case '/':
s.Append(c);
break;
case 'b':
s.Append('\b');
break;
case 'f':
s.Append('\f');
break;
case 'n':
s.Append('\n');
break;
case 'r':
s.Append('\r');
break;
case 't':
s.Append('\t');
break;
case 'u':
var hex = new char[4];
for (int i=0; i< 4; i++) {
hex[i] = NextChar;
}
s.Append((char) Convert.ToInt32(new string(hex), 16));
break;
}
break;
default:
s.Append(c);
break;
}
}
return s.ToString();
}
object ParseNumber() {
string number = NextWord;
if (number.IndexOf('.') == -1) {
long parsedInt;
Int64.TryParse(number, out parsedInt);
return parsedInt;
}
double parsedDouble;
Double.TryParse(number, out parsedDouble);
return parsedDouble;
}
void EatWhitespace() {
while (Char.IsWhiteSpace(PeekChar)) {
json.Read();
if (json.Peek() == -1) {
break;
}
}
}
char PeekChar {
get {
return Convert.ToChar(json.Peek());
}
}
char NextChar {
get {
return Convert.ToChar(json.Read());
}
}
string NextWord {
get {
StringBuilder word = new StringBuilder();
while (!IsWordBreak(PeekChar)) {
word.Append(NextChar);
if (json.Peek() == -1) {
break;
}
}
return word.ToString();
}
}
TOKEN NextToken {
get {
EatWhitespace();
if (json.Peek() == -1) {
return TOKEN.NONE;
}
switch (PeekChar) {
case '{':
return TOKEN.CURLY_OPEN;
case '}':
json.Read();
return TOKEN.CURLY_CLOSE;
case '[':
return TOKEN.SQUARED_OPEN;
case ']':
json.Read();
return TOKEN.SQUARED_CLOSE;
case ',':
json.Read();
return TOKEN.COMMA;
case '"':
return TOKEN.STRING;
case ':':
return TOKEN.COLON;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '-':
return TOKEN.NUMBER;
}
switch (NextWord) {
case "false":
return TOKEN.FALSE;
case "true":
return TOKEN.TRUE;
case "null":
return TOKEN.NULL;
}
return TOKEN.NONE;
}
}
}
/// <summary>
/// Converts a IDictionary / IList object or a simple type (string, int, etc.) into a JSON string
/// </summary>
/// <param name="json">A Dictionary&lt;string, object&gt; / List&lt;object&gt;</param>
/// <returns>A JSON encoded string, or null if object 'json' is not serializable</returns>
public static string Serialize(object obj) {
return Serializer.Serialize(obj);
}
sealed class Serializer {
StringBuilder builder;
Serializer() {
builder = new StringBuilder();
}
public static string Serialize(object obj) {
var instance = new Serializer();
instance.SerializeValue(obj);
return instance.builder.ToString();
}
void SerializeValue(object value) {
IList asList;
IDictionary asDict;
string asStr;
if (value == null) {
builder.Append("null");
} else if ((asStr = value as string) != null) {
SerializeString(asStr);
} else if (value is bool) {
builder.Append((bool) value ? "true" : "false");
} else if ((asList = value as IList) != null) {
SerializeArray(asList);
} else if ((asDict = value as IDictionary) != null) {
SerializeObject(asDict);
} else if (value is char) {
SerializeString(new string((char) value, 1));
} else {
SerializeOther(value);
}
}
void SerializeObject(IDictionary obj) {
bool first = true;
builder.Append('{');
foreach (object e in obj.Keys) {
if (!first) {
builder.Append(',');
}
SerializeString(e.ToString());
builder.Append(':');
SerializeValue(obj[e]);
first = false;
}
builder.Append('}');
}
void SerializeArray(IList anArray) {
builder.Append('[');
bool first = true;
foreach (object obj in anArray) {
if (!first) {
builder.Append(',');
}
SerializeValue(obj);
first = false;
}
builder.Append(']');
}
void SerializeString(string str) {
builder.Append('\"');
char[] charArray = str.ToCharArray();
foreach (var c in charArray) {
switch (c) {
case '"':
builder.Append("\\\"");
break;
case '\\':
builder.Append("\\\\");
break;
case '\b':
builder.Append("\\b");
break;
case '\f':
builder.Append("\\f");
break;
case '\n':
builder.Append("\\n");
break;
case '\r':
builder.Append("\\r");
break;
case '\t':
builder.Append("\\t");
break;
default:
int codepoint = Convert.ToInt32(c);
if ((codepoint >= 32) && (codepoint <= 126)) {
builder.Append(c);
} else {
builder.Append("\\u");
builder.Append(codepoint.ToString("x4"));
}
break;
}
}
builder.Append('\"');
}
void SerializeOther(object value) {
// NOTE: decimals lose precision during serialization.
// They always have, I'm just letting you know.
// Previously floats and doubles lost precision too.
if (value is float) {
builder.Append(((float) value).ToString("R"));
} else if (value is int
|| value is uint
|| value is long
|| value is sbyte
|| value is byte
|| value is short
|| value is ushort
|| value is ulong) {
builder.Append(value);
} else if (value is double
|| value is decimal) {
builder.Append(Convert.ToDouble(value).ToString("R"));
} else {
SerializeString(value.ToString());
}
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5f7a61f19ec6f294a8c26f6050e199dd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 23ccfd9225778c242b44692e9fa9540a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8e00bc6bd174cae4c869cf1b29186e43
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,103 @@
using GCloud.UQM;
using System;
using System.Collections;
using System.Threading;
using UnityEngine;
public class CrashSightAnrMonitor
{
private static CrashSightMonoBehaviour monoBehaviour = CrashSightMonoBehaviour.Instance;
private static int anrTimeoutMs = 5000;
private static int detectionTimeoutMs = 1000;
protected static bool Paused { get; private set; } = false;
private static int ticksSinceUiUpdate = 0;
private static bool reported = false;
private static bool running = false;
private static Thread thread;
public static void Start(int timeoutMs = 5000)
{
if (running)
{
return;
}
else
{
running = true;
}
anrTimeoutMs = timeoutMs;
detectionTimeoutMs = Math.Max(1, anrTimeoutMs / 5);
monoBehaviour.ApplicationPausing += () => Paused = true;
monoBehaviour.ApplicationResuming += () => Paused = false;
monoBehaviour.ApplicationQuitting += () => Stop();
thread = new Thread(Run)
{
Name = "CrashSight-ANR-Monitor",
IsBackground = true,
Priority = System.Threading.ThreadPriority.BelowNormal,
};
thread.Start();
monoBehaviour.StartCoroutine(UpdateUiStatus());
}
public static void Stop()
{
running = false;
}
private static IEnumerator UpdateUiStatus()
{
UQMCrash.SetEngineMainThread();
var waitForSeconds = new WaitForSecondsRealtime((float)detectionTimeoutMs / 1000);
yield return waitForSeconds;
while (running)
{
ticksSinceUiUpdate = 0;
reported = false;
yield return waitForSeconds;
}
}
private static void Run()
{
try
{
while (running)
{
ticksSinceUiUpdate += detectionTimeoutMs;
Thread.Sleep(detectionTimeoutMs);
if (Paused)
{
ticksSinceUiUpdate = 0;
}
else if (ticksSinceUiUpdate >= anrTimeoutMs && !reported)
{
Report();
reported = true;
}
}
}
catch (Exception ex)
{
UQMLog.LogError("CrashSightAnrMonitor meets an unknown error = \n" + ex.Message + "\n" + ex.StackTrace);
}
}
private static void Report()
{
string message = $"Application not responding for at least {anrTimeoutMs} ms.";
UQMLog.Log(message);
UQMCrash.ProcessEngineAnr(1);
}
}
public class UnityAnrException : Exception
{
internal UnityAnrException() : base() { }
internal UnityAnrException(string message) : base(message) { }
internal UnityAnrException(string message, Exception innerException) : base(message, innerException) { }
}

View File

@ -0,0 +1,89 @@
// ----------------------------------------
//
// CrashSightCallbackDelegate.cs
//
// Author:
// Yeelik,
//
// Copyright (c) 2015 CrashSight. All rights reserved.
//
// ----------------------------------------
//
using UnityEngine;
public abstract class CrashSightCallback
{
private static volatile bool isQuitting = false;
private static object quitLocker = new object();
static CrashSightCallback()
{
// 注册应用退出事件监听器
Application.quitting += OnApplicationQuitting;
}
/// <summary>
/// 应用退出时的回调
/// </summary>
private static void OnApplicationQuitting()
{
lock (quitLocker)
{
isQuitting = true;
}
}
/// <summary>
/// 检查应用是否正在退出
/// </summary>
public static bool IsQuitting()
{
lock (quitLocker)
{
return isQuitting;
}
}
public abstract string OnCrashBaseRetEvent(int methodId, int crashType);
}
public abstract class CrashSightLogCallback
{
private static volatile bool isQuitting = false;
private static object quitLocker = new object();
static CrashSightLogCallback()
{
// 注册应用退出事件监听器
Application.quitting += OnApplicationQuitting;
}
/// <summary>
/// 应用退出时的回调
/// </summary>
private static void OnApplicationQuitting()
{
lock (quitLocker)
{
isQuitting = true;
}
}
/// <summary>
/// 检查应用是否正在退出
/// </summary>
public static bool IsQuitting()
{
lock (quitLocker)
{
return isQuitting;
}
}
public abstract string OnSetLogPathEvent(int methodId, int crashType);
public abstract void OnLogUploadResultEvent(int methodId, int crashType, int result);
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ba1b54454a2619141b38d419338ee9aa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,59 @@
using System;
using UnityEngine;
[AddComponentMenu("")]
public partial class CrashSightMonoBehaviour : MonoBehaviour
{
private static CrashSightMonoBehaviour _instance;
public static CrashSightMonoBehaviour Instance
{
get
{
if (_instance == null)
{
var gameObject = new GameObject("CrashSightMonoBehaviour") { hideFlags = HideFlags.HideAndDontSave };
DontDestroyOnLoad(gameObject);
_instance = gameObject.AddComponent<CrashSightMonoBehaviour>();
}
return _instance;
}
}
public event Action ApplicationResuming;
public event Action ApplicationPausing;
public event Action ApplicationQuitting;
internal bool _isRunning = true;
public void UpdatePauseStatus(bool paused)
{
if (paused && _isRunning)
{
_isRunning = false;
ApplicationPausing?.Invoke();
}
else if (!paused && !_isRunning)
{
_isRunning = true;
ApplicationResuming?.Invoke();
}
}
internal void OnApplicationPause(bool pauseStatus) => UpdatePauseStatus(pauseStatus);
internal void OnApplicationFocus(bool hasFocus) => UpdatePauseStatus(!hasFocus);
private void OnApplicationQuit()
{
ApplicationQuitting?.Invoke();
Destroy(gameObject);
}
private void Awake()
{
DontDestroyOnLoad(gameObject);
}
}

View File

@ -0,0 +1,161 @@
using AOT;
using System;
using System.Runtime.InteropServices;
using UnityEngine;
// 使用前请先打开ENABLE_CRASHSIGHT_STACKTRACE宏
public class CrashSightStackTrace
{
public static bool enable = false;
//CrashSightStackTrace开关仅在il2cpp编译时允许打开
public static void setEnable(bool enable)
{
#if ENABLE_IL2CPP && ENABLE_CRASHSIGHT_STACKTRACE
CrashSightStackTrace.enable = enable;
#endif
}
#if UNITY_ANDROID
public const string lib = "il2cpp";
#elif UNITY_IOS
public const string lib = "__Internal";
#endif
#if (UNITY_ANDROID || UNITY_IOS) && !UNITY_EDITOR && ENABLE_IL2CPP && ENABLE_CRASHSIGHT_STACKTRACE
[DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
public static extern void il2cpp_current_thread_walk_frame_stack(Il2CppFrameWalkFunc func, IntPtr data);
[DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr il2cpp_method_get_name(IntPtr method);
[DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
public static extern int il2cpp_method_get_param_count(IntPtr method);
[DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr il2cpp_method_get_class(IntPtr method);
[DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr il2cpp_method_get_param(IntPtr method, int index);
[DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr il2cpp_class_get_name(IntPtr klass);
[DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr il2cpp_class_get_namespace(IntPtr klass);
[DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr il2cpp_type_get_name(IntPtr type);
[DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr il2cpp_class_get_declaring_type(IntPtr klass);
[DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr il2cpp_class_from_il2cpp_type(IntPtr type);
#if UNITY_2018_1_OR_NEWER
[DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
public static extern bool il2cpp_type_is_byref(IntPtr type);
#endif
//type结构体用于直接读取指针指向的内容能不用则不用尽量使用il2cpp的API
public struct Il2CppType
{
public IntPtr unionData;
public Int16 attrs;
public Byte type;
public Byte num_mods;
public bool byref()
{
return (num_mods & 64) != 0;//0b01000000
}
};
public delegate void Il2CppFrameWalkFunc(IntPtr info, IntPtr user_data);
//FrameWalk回调每次处理一帧的信息
[MonoPInvokeCallback(typeof(Il2CppFrameWalkFunc))]
public static void Il2CppFrameWalkFuncImp(IntPtr info, IntPtr data)
{
string stackFrame = "";
IntPtr method = (IntPtr)Marshal.PtrToStructure(info, typeof(IntPtr));
string name = Marshal.PtrToStringAnsi(il2cpp_method_get_name(method));
IntPtr klass = il2cpp_method_get_class(method);
string klassName = Marshal.PtrToStringAnsi(il2cpp_class_get_name(klass));
string klassNamespaze = Marshal.PtrToStringAnsi(il2cpp_class_get_namespace(klass));
//模板类等,额外执行命名空间查找
if(string.IsNullOrEmpty(klassNamespaze))
{
IntPtr declaring_type = il2cpp_class_get_declaring_type(klass);
if (declaring_type != IntPtr.Zero)
{
klassNamespaze = Marshal.PtrToStringAnsi(il2cpp_class_get_namespace(declaring_type));
}
}
if (!string.IsNullOrEmpty(klassNamespaze))
stackFrame += klassNamespaze + ".";
stackFrame += klassName + ":" + name + "(";
//遍历参数
int paraCount = il2cpp_method_get_param_count(method);
for (int i = 0; i < paraCount; i++)
{
if (i != 0)
{
stackFrame += ", ";
}
IntPtr type = il2cpp_method_get_param(method, i);
IntPtr typeClass = il2cpp_class_from_il2cpp_type(type);
string typeName = Marshal.PtrToStringAnsi(il2cpp_class_get_name(typeClass));
stackFrame += typeName;
#if UNITY_2018_1_OR_NEWER
//il2cpp_type_is_byref可用时直接使用它判断参数是否为引用
bool byref = il2cpp_type_is_byref(type);
if (byref)
{
stackFrame += "&";
}
#else
//il2cpp_type_is_byref不可用时只能通过指针访问结构可能不安全
Il2CppType typeimpl = (Il2CppType)Marshal.PtrToStructure(type, typeof(Il2CppType));
if (typeimpl.byref())
{
stackFrame += "&";
}
#endif
}
stackFrame += ")\n";
stackTrace = stackFrame + stackTrace;
}
#endif
static string stackTrace;
//stacktrace入口默认使用StackTraceUtility.ExtractStackTrace()需要setEnable来切换到CrashSightStackTrace
public static string ExtractStackTrace()
{
if (!enable)
{
return StackTraceUtility.ExtractStackTrace();
}
stackTrace = string.Empty;
#if (UNITY_ANDROID || UNITY_IOS) && !UNITY_EDITOR && ENABLE_IL2CPP && ENABLE_CRASHSIGHT_STACKTRACE
il2cpp_current_thread_walk_frame_stack(Il2CppFrameWalkFuncImp, new IntPtr());
//有些il2cpp版本会把il2cpp_current_thread_walk_frame_stack打出来有些则不会判断并丢弃
int line1 = stackTrace.IndexOf('\n');
int line2 = stackTrace.IndexOf('\n', line1 + 1);
if (stackTrace.Substring(0, line1) == "CrashSightStackTrace:ExtractStackTrace()")
{
stackTrace = stackTrace.Substring(line1 + 1);
}
else
{
stackTrace = stackTrace.Substring(line2 + 1);
}
#endif
return stackTrace;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 134a5ecbf5aa66d4d9214b3669828a24
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,2 @@
Define_list:
- SDK_CRASHSIGHT

View File

@ -1 +1 @@
0.0.1
0.0.2