Project introduction
In the IT industry, especially for game projects, there is no way to test all possible situations before launching, so we often need some online bug collection tools, and Tencent’s Bugly is a very good tool. This project is to integrate Bugly into CocosCreator, the latest development tool for Cocos, a popular cross-platform game engine.
Project background
As far as I know, there are two main ways of bugly access:
- Use the “outdated” Cocos plugin
- Use js’s window.onerror interface
This article will introduce the third way, c++ throws an exception and reports it natively. The benefits of this way are:
- In contrast to the Cocos plugin, there is no need to plugin a separate c++ SDK, and android does not need to modify mk files.
- This method is more flexible than js script error reporting, and is easier to make a public module.
Access to the steps
Create CCC project and compile native project
First we create a CCC project
The script is mounted as follows
As you can see, we did not drag in the label node, so this code will report an error. Then we build the native project, because we need to introduce ios and Android access here, so we build android and ios platform, after building the directory
The CCC I use is 2.4.X version, which varies slightly from version to version, but does not affect access.
Android terminal access
If you are familiar with Android, please refer to the official document for access. If you are not familiar with Android, please refer to my access method
To integrate the SDK
Open build.gradle in Module(app directory), add bugly dependencies, and add the code
dependencies {
implementation fileTree(dir: '.. /libs'.include: ['*.jar'.'*.aar'])
implementation fileTree(dir: 'libs'.include: ['*.jar'.'*.aar'])
implementation fileTree(dir: "/ Applications/CocosCreator/Creator / 2.4.3 - rc. 1 / CocosCreator. App/Contents/Resources/cocos2d - x/cocos/platform/android/Java /libs".include: ['*.jar'])
implementation project(':libcocos2dx')
implementation 'com.tencent.bugly:crashreport:latest.release'
implementation 'com.tencent.bugly:nativecrashreport:latest.release'
}
Copy the code
“Latest. release” indicates the latest version. It is recommended that you specify the latest version, so that later compilation will be faster.
Initialization and method implementation
See a lot of developers who are not familiar with Android, according to the official example, many methods written in AppActivity, in fact, this is not beautiful and not conducive to the later maintenance, recommend you to clear module division, here I create a buglyAgent. Java file under the package, to achieve the function of Bugly. This demo mainly introduces exception reporting, so two methods are implemented: initialization and exception reporting. Detailed code
package cn.xyzzlky.bugly;
import android.content.Context;
import com.tencent.bugly.crashreport.CrashReport;
import java.util.Map;
public class BuglyAgent {
public static void initSDK(Context context, String appId) {
CrashReport.initCrashReport(context.getApplicationContext(), appId, false);
}
public static void postException(int category, String name, String reason, String stack){
postException(category, name, reason, stack, null);
}
public static void postException(int category, String name, String reason, String stack, Map<String, String> extraInfo){ CrashReport.postException(category, name, reason, stack, extraInfo); }}Copy the code
So I set the last parameter to null. Don’t forget to initialize the SDK in the appropriate place (such as AppActivity)
public class AppActivity extends Cocos2dxActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
BuglyAgent.initSDK(this."Bugly的APPID");
// ...}}Copy the code
Android’s native access ends here. You just need to remember the package name, class name, and method name of the exception reporting method that you implemented, such as in my case, cn.xyzzlky.bugly, BuglyAgent, and postException.
IOS access
The same as above, if you are familiar with ios, please refer to the official document to access, if not, you can refer to my method
The SDK access
- If you have Cocoa installed, connect directly to POD
- If not, you can either install Cocoa and use method 1, or download it and refer to the official documentation, noting the options and dependency libraries
Initialization and method implementation
The buglyAgent.h code is posted directly
@interface BuglyAgent : NSObject
+ (void)initSdk:(NSString *)appId;
+ (void)reportExceptionWithCategory:(NSUInteger)category name:(NSString *)name reason:(NSString *)reason callStack:(NSArray *)stackArray extraInfo:(NSDictionary *)info terminateApp:(BOOL)terminate;
@end
Copy the code
BuglyAgent. Mm code
#import "BuglyAgent.h"
#import <Bugly/Bugly.h>
@implementation BuglyAgent
+ (void)initSdk:(NSString *)appId
{
[Bugly startWithAppId:appId];
}
+ (void)reportExceptionWithCategory:(NSUInteger)category name:(NSString *)name reason:(NSString *)reason callStack:(NSArray *)stackArray extraInfo:(NSDictionary *)info terminateApp:(BOOL)terminate
{
[Bugly reportExceptionWithCategory:category name:name reason:reason callStack:stackArray extraInfo:info terminateApp:terminate];
}
@end
Copy the code
Again, we initialize the SDK at the appropriate location (such as appController.m)
// ...
#import "BuglyAgent.h"
// ...
@implementation AppController
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// ...
[BuglyAgent initSdk:@ "Bugly APPID"];
// ...
}
Copy the code
IOS way of accessing to the end, also remember the name of the class and method name, my class name is BuglyAgent, for example, the method name is reportExceptionWithCategory: name: “reason: callStack: extraInfo: terminateApp:
C++ code modification
Catch exceptions
Because CCC is very close the interface exposed the exception handling, so we directly use, location in the * * / frameworks/runtime – SRC/Class/AppDelegate. CPP, as follows:
se->setExceptionCallback([] (const char *location, const char *message, const char *stack) {
// Send exception information to server like Tencent Bugly.
cocos2d::log("\nUncaught Exception:\n - location : %s\n - msg : %s\n - detail : \n %s\n", location, message, stack);
});
Copy the code
Calling a Java method
C++ call Java methods, using CCC JniHelper class is good, call way
JniHelper::callStaticVoidMethod("The name of the class"."Method name". Parameters);Copy the code
Note here that the class name is the full path, and the “.” of the package name needs to be replaced by “/”, for example, the method we call is
JniHelper::callStaticVoidMethod("cn/xyzzlky.bugly/BuglyAgent"."postException".5."JSError", message, stack);
Copy the code
Parameter Description:
- 5 is a sign of JS error, Bugly defined, reference com. Tencent. Bugly. BuglyStrategy.
- Wrong name, custom is ok, Bugly defined it this way.
- The wrong reason
- Wrong stack
As mentioned above, Android is already plugged in. Run it directly and Bugly will see the error.
Calling the OC method
Android is in, what about ios? Do you call oc directly as well? C++ does not support direct calls to oc. So we need to write a bridge layer of C to complete the access of OC. Start by feeding the bridge code to the CrashReport.h code
class CrashReport
{
public:
static void reportException(const char* msg, const char* traceback);
CrashReport();
};
Copy the code
CrashReport. Mm code
#include "CrashReport.h"
#define BUGLY_CLASS @"BuglyAgent"
#define BUGLY_METHOD_EXCEPTION @"reportExceptionWithCategory:name:reason:callStack:extraInfo:terminateApp:"
CrashReport::CrashReport(){
}
void CrashReport::reportException(const char* msg, const char* traceback) {
Class clazz = NSClassFromString(BUGLY_CLASS);
if (clazz) {
SEL selector = NSSelectorFromString(BUGLY_METHOD_EXCEPTION);
NSMethodSignature* signature = [clazz methodSignatureForSelector:selector];
NSInteger category = 5;
NSString *name = @"JSError";
NSString *reason = NULL == msg ? @"" : @(msg);
NSString *track = NULL == traceback ? @"" : @(traceback);
NSArray *trackArray = [track componentsSeparatedByString:@"\n"];
NSDictionary *info = nil;
BOOL terminate = NO;
if (signature) {
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
if (invocation) {
[invocation setTarget:clazz];
[invocation setSelector:selector];
[invocation setArgument:&category atIndex:2];
[invocation setArgument:&name atIndex:3];
[invocation setArgument:&reason atIndex:4];
[invocation setArgument:&trackArray atIndex:5];
[invocation setArgument:&info atIndex:6];
[invocation setArgument:&terminate atIndex:7]; [invocation invoke]; }}}}Copy the code
The code meaning here is consistent with Java. It can then be called by c++
// ...
#include "CrashReport.h"
// ...
CrashReport::reportException(message, stack);
// ...
Copy the code
Also, running ios, you can see the logs in the background.
The last step
#include “crashReport. h” error, by the way, because we did not modify mk file, in Android, we can not call this method, so we need to distinguish platform, at the same time for convenient maintenance, We’re going to make the android class name constant, so the header becomes
#if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#define BUGLY_CLZ_NAME "cn/xyzzlky/bugly/BuglyAgent"
#elif(CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
#include "CrashReport.h"
#endif
Copy the code
And the same is true of where you call it
se->setExceptionCallback([] (const char *location, const char *message, const char *stack) {
// Send exception information to server like Tencent Bugly.
cocos2d::log("\nUncaught Exception:\n - location : %s\n - msg : %s\n - detail : \n %s\n", location, message, stack);
#if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
JniHelper::callStaticVoidMethod(BUGLY_CLZ_NAME, "postException".5."JSError", message, stack);
#elif(CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
CrashReport::reportException(message, stack);
#endif
});
Copy the code
Here, we’re finally done with our work.
See the effect
Here are some suggestions
- Backups of JAVASCRIPT files are in “JS Backups (Useful for debugging)”. Backups are recommended for every online package
- Js error may be inconsistent with app version because there may be a heat attack. It is recommended that you also report the JS version to Bugly
conclusion
I didn’t know there were any native call methods, but they are based on the CocosPlugin API, so there are some things to explore.
This article is participating in the “Nuggets 2021 Spring Recruitment Campaign”, click to see the details of the campaign