(插播)unity的 异常捕捉和 ios Android 崩溃信息的捕捉。
近期 做些准备性得工作和有意思的事情。所以近期做了一个适合ios和android 错误信息捕捉的unity插件。
两个功能,app崩溃也就是闪退 是开发人员 非常头疼的一件事,还有就是一些莫名得错误 有时候也会困扰着我们。如今,unity已经封装得挺好了,及时出现数组越界,和空对象这样严重得错误也不会崩溃。听着挺好。可是这给开发人员带了非常多烦恼啊。由于有时候可能出错了 你要跟就不知道 ,在什么地方出得错误啊。所以我们要想办法去解决问题。
我们都知道及时app崩溃,事实上后台还是在执行得 仅仅只是是 到了还有一个线程去处理崩溃得一些问题。那好我们就能够去捕捉到错误,供我们去理解这个问题。
首先 我们先针对 ios闪退得错误得问题。我们知道 如今ios还是才去得OC编程,身为一个编译性得语言,一般非常小得一个错误都会造成整个app得崩溃。
接下来 我们说下原理。 对于 IOS的机制是。它专门有一个类来处理异常错误。
那就是NSException类。来处理各种错误得一个类。我们要的就是这个类中得一个通知,就是 在app出现异常崩溃的事后会通知得一个方法C语言的NSSetUncaughtExceptionHandler。我们就是用这种方法来进行 异常注冊。
NSSetUncaughtExceptionHandler(&caughtExceptionHandler);
当中 caughtExceptionHandler是自己写得类中得一个C语言得方法。
void caughtExceptionHandler(NSException *e){}
能够看到 在这种方法中我们就能够拿到NSException得错误得指针。
就能够得到全部得错误得信息。
这里知道了一半。信息我们是得到了,可是app如今是处于崩溃中,我们想让我们的错误信息传到server或者返回给开发人员得处理平台。那我们得线程必须等待才干够。这样才干给我们时间把错误信息上传到处理平台。
那怎么才干把线程堵塞调那 正好 ios有线程进入等待得方法CFRunLoopRunInMode()
好了想好这个多 我们開始 进行实施了。
这是 异常获取得方法,把此方法 进行注冊 也就是
-(void) _registerException{
NSSetUncaughtExceptionHandler(&caughtExceptionHandler);
}
void caughtExceptionHandler(NSException *e){
NSString *currentTime = [[VKCatchCrash shareCatchCrash] getCurrentTime];
CFRunLoopRef runLoop = CFRunLoopGetCurrent();
CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);
NSArray *arr = [e callStackSymbols];
NSString *reason = [e reason];
NSString *name = [e name];
NSMutableDictionary *dic = [[NSMutableDictionary alloc]init];
[dic setValue:[[VKCatchCrash shareCatchCrash] _getDeviceInfo] forKey:@"device"];
[dic setValue:arr forKey:@"callStackSymbols"];
[dic setValue:reason forKey:@"reason"];
[dic setValue:name forKey:@"name"];
[dic setObject:currentTime forKey:@"time"];
NSError *error = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic
options:NSJSONWritingPrettyPrinted
error:&error];
if ([jsonData length] > 0 && error == nil){
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSString *path = [[VKCatchCrash shareCatchCrash] fullScreenshots:currentTime];
//if([[VKCatchCrash shareCatchCrash] checkNetwork]){
[Upload startUpload:[Upload initUpBackBlock:^(NSData *data, NSURLResponse *response, NSError *error) {
NSFileManager *manager = [NSFileManager defaultManager];
if([manager fileExistsAtPath:path]){
[manager removeItemAtPath:path error:nil];
}
} upUrl:HOST upDelegate:nil formName:@"fileField" filePath:path contentKey:[[NSArray alloc] initWithObjects:@"bug", nil] contentValue:[[NSArray alloc] initWithObjects:jsonString, nil]]];
// }
NSLog(@"%@",jsonString);
[[VKCatchCrash shareCatchCrash] performSelectorOnMainThread:@selector(alertUploadBug) withObject:nil waitUntilDone:YES];
while (!dismiss)
{
for (NSString *mode in (__bridge NSArray *)allModes)
{
CFRunLoopRunInMode((__bridge CFStringRef)mode, 0, false);
}
}
CFRelease(allModes);
NSSetUncaughtExceptionHandler(NULL);
}else{
NSLog(@"nil");
}
}
警告框提示app闪退。
-(void)alertUploadBug{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"产生莫名得崩溃,报告正在发送server。" message:nil delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
[alert show];
}
当前时间
-(NSString *)getCurrentTime{
NSDate * senddate=[NSDate date];
NSDateFormatter *dateformatter=[[NSDateFormatter alloc] init];
[dateformatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"];
NSString * locationString=[dateformatter stringFromDate:senddate];
return locationString;
}
这里还用到了一个 自己写的额一个上传得类VKHttpManager,回来我会上传 源代码。
基本信息就这么多。详情能够看下 源代码。
以下我们 我们来说下Android得闪退得异常捕获。
Android相对于ios比較简单,仅仅要使用一个类来接口UncaughtExceptionHandler就能够了
然后有借口得方法,会自己主动调用该回调。
public class MyCrashHandler implements UncaughtExceptionHandler{
@Override
public void uncaughtException(Thread thread, Throwable ex) {
}
}
当中 Throwable得异常对象就是我们须要得异常对象。
当中这里也有 和ios相似得地方 那就是 线程堵塞
Looper.prepare();
Looper.loop();
这里有一个地方要注意得就是 在安卓中 unity调用 AndroidUI得东西 要使用 UI线程不然是无法显示。
详情见以下得源代码
UnityPlayer.currentActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
}
}。
然后 unity里我们还要做些东西来捕获unity得异常和对ios和Android进行对接得一些东西。
using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;
public class CatchCrash : MonoBehaviour { private static string HOST ="http://192.168.1.240/game/";
private static string currentTime = ""; #if UNITY_IPHONE
[DllImport ("__Internal")]
private static extern void registerException (string host);
[DllImport ("__Internal")]
private static extern void createBug ();
[DllImport ("__Internal")]
private static extern void unityBugAlert (string msg);
[DllImport ("__Internal")]
private static extern string getDeviceInfo (); #elif UNITY_ANDROID
AndroidJavaClass jc = null;
AndroidJavaObject jo = null;
#endif
// Use this for initialization
void Awake () { #if UNITY_EDITOR #elif UNITY_IPHONE || UNITY_ANDROID
DontDestroyOnLoad (gameObject);
Application.RegisterLogCallback(OnLog);
#endif #if UNITY_IPHONE
registerException (HOST);
#elif UNITY_ANDROID
jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
jo.Call("registerException",HOST);
#endif
} void OnLog (string message, string stacktrace, LogType type)
{
if (type == LogType.Exception)
{
currentTime = getcurrentTime().ToString();
string butMsg = "{\n"+
"\"message\":" +"\""+message.Replace("\n","")+"\""+
",\n\"stacktrace\":"+"\""+stacktrace.Replace("\n","")+"\""+
",\n\"time\":"+"\""+currentTime+"\""
+"\n" +
"\"device\":" +"\""+
#if UNITY_IPHONE
getDeviceInfo().Replace("\n","")+"\""+
#elif UNITY_ANDROID
jo.CallStatic<string>("getDeviceInfo").Replace("\n","")+"\""+
#endif
"\n}";
StartCoroutine(uploadBug(butMsg));
#if UNITY_IPHONE
unityBugAlert (butMsg);
#elif UNITY_ANDROID
jo.CallStatic("unityBugAlert",butMsg);
#endif
}
} IEnumerator uploadBug(string butMsg){
yield return new WaitForEndOfFrame();
int width = Screen.width;
int height = Screen.height;
Texture2D tex = new Texture2D (width,height,TextureFormat.RGB24, false);
tex.ReadPixels(new Rect(0, 0, width, height), 0, 0 );
tex.Apply();
byte [] bytes = tex.EncodeToPNG (); WWWForm form = new WWWForm();
form.AddField ("bug",butMsg);
form.AddBinaryData ("fileField",bytes,currentTime+".png","image/png"); WWW w = new WWW (HOST,form);
yield return w;
if (w.error != null) {
Debug.Log (" upload bug erro");
} else {
Debug.Log (" upload bug finish");
}
} public static string getcurrentTime()
{
System.DateTime now = System.DateTime.Now;
return now.Year + "-" + now.Month + "-" + now.Day + " " + now.Hour + ":" + now.Minute + ":" + now.Second;
}
}
(插播)unity的 异常捕捉和 ios Android 崩溃信息的捕捉。的更多相关文章
- WEB通知和React Native之即时通讯(iOS Android)
WEB通知和React Native之即时通讯(iOS Android) 一,需求分析 1.1,允许服务器主动发送信息给客户端,客户端能监听到并且能接收. 1.2,为了方便同一个系统内的用户可以指定某 ...
- 常用获取Android崩溃日志和IOS崩溃日志的几种方法
一:前言 在日常测试app时,经常会遇到崩溃问题,测试快速抓取到崩溃日志可以有效方便开发进行定位,快速解决问题所在测试做到测试分析,定位是非常重要的,这也是判断一个测试能力指标的一大维度. 二:And ...
- 封装 React Native 原生组件(iOS / Android)
封装 React Native 原生组件(iOS / Android) 在 React Native中,有很多种丰富的组件了,例如 ScrollView.FlatList.SectionList.Bu ...
- Xamarin体验:使用C#开发iOS/Android应用
Xamarin是Mono创始人Miguel de Icaza创建的公司,旨在让开发者可以用C#编写iOS, Android, Mac应用程序,也就是跨平台移动开发. 简介 Xamarin是基于Mo ...
- Ionic中使用Chart.js进行图表展示以及在iOS/Android中的性能差异
Angular Chart 简介 在之前的文章中介绍了使用 Ionic 开发跨平台(iOS & Android)应用中遇到的一些问题的解决方案. 在更新0.1.3版本的过程中遇到了需要使用图表 ...
- iOS/Android 浏览器(h5)及微信中唤起本地APP
在移动互联网,链接是比较重要的传播媒质,但很多时候我们又希望用户能够回到APP中,这就要求APP可以通过浏览器或在微信中被方便地唤起. 这是一个既直观又很好的用户体验,但在实现过程中会遇到各种问题: ...
- fir.im Weekly - iOS/Android 应用程序架构解析
假如问你一个iOS or Android app的架构,你会从哪些方面来说呢? 本期 fir.im Weekly 收集了关于 iOS/Android 开发资源,也加入了一些关于 Web 前端方面的分 ...
- 【原】常见CSS3属性对ios&android&winphone的支持
2个月前,我在博文<webapp开发中兼容Android4.0以下版本的css hack>中写过“那对于做移动网页开发的同事来说,一般只要做好webkit内核浏览器的展现效果就行了” ,在 ...
- iOS / Android 移动设备中的 Touch Icons
上次转载了一篇<将你的网站打造成一个iOS Web App>,但偶然发现这篇文章的内容有些是错误的——准确来说也不是错误,只是不适合自半年前来的情况了(也可以说是iOS7 之后的时间)—— ...
随机推荐
- Android开发之Buidler模式初探结合AlertDialog.Builder解说
什么是Buidler模式呢?就是将一个复杂对象的构建与它的表示分离,使得相同的构建过程能够创建不同的表示.Builder模式是一步一步创建一个复杂的对象,它同意用户能够仅仅通过指定复杂对象 ...
- 測试之路3——对照XML文件2
距离上一篇对照xml文件隔了非常久,并不代表一直做了那么久. 事实上上一次对照xml文件一直出错,事实上我忽略了一个非常easy的问题:我从根文件夹下得到的全部孩子,是这个根下的,而xml文件的组织形 ...
- oracle转Mysql中,varchar2(10)和number应该转换为什么类型? (转)
一. varchar2(10)和number应该转换为什么类型? oracle转成mysql时:varchar2(10)可以转成varchar(10)number则要看oracle中存储的具体是什么类 ...
- 三种方法让你的Service不被“一键加速”和系统杀掉
基本上大家都知道提高service优先级能够在非常大程度上让你的service免于由于内存不足而被kill,当然系统仅仅是在此时先把优先级低的kill掉,假设内存还是不够,也会把你的service干掉 ...
- 悼念传奇,约翰询问·纳什和他的妻子艾丽西亚致敬,创建一个传奇,爱数学
约翰·阅读·纳什的传记.我渴望录制通道 我一直相信数字,无论逻辑方程使我们认为.但这种追求一生的后,我问自己:"这是什么逻辑?谁决定的理由?"我的探索让我从物理到形而上,最后到了妄 ...
- DIY.NETORM帧——技术储备(1)Attribute
1.他是什么 ? 首先.我们当然Attribute它是一类,以下是一msdn文档对它的描写叙述: 公共语言执行时同意你加入类似keyword的描写叙述声明,叫做attributes, ...
- 趣味Java算法题(附答案)
[程序1] 题目:古典问题:有一对兔子,从出生后第3个月起每一个月都生一对兔子,小兔子长到第三个月后每一个月又生一对兔子,假如兔子都不死,问每一个月的兔子总数为多少? //这是一个菲波拉契 ...
- C++ Primer 学习笔记_40_STL实践与分析(14)--概要、先来看看算法【上】
STL实践与分析 --概述.初窥算法[上] 标准库容器定义的操作很少.并没有给容器加入大量的功能函数.而是选择提供一组算法,这些算法大都不依赖特定的容器类型,是"泛型"的. ...
- Oracle GoldenGate (以下简称ogg)在异种移植os同一种db之间的数据同步。
Oracle GoldenGate (以下简称ogg)在异种移植os同一种db之间的数据同步. ogg要实现的功能: 同步可以细化到单个表,满足特定的where条件rows同步,称号column同步. ...
- Cocos2d-x学习笔记(五岁以下儿童) 精灵两种方式播放动画
这几天在看控件类,临时没有想好实际运用的方向.单纯的创建网上已经有非常多这方面的样例,我就不写了.接下来是学习精灵类.精灵类若是单独学习也是非常easy.于是我加了一些有关动画方面的知识点与精灵 ...