关于reactnatice android 集成离线sourcemap的
来源:互联网 发布:mac安装第三方软件 编辑:程序博客网 时间:2024/05/18 00:01
rn打离线包往往会遇到一个问题,代码报错的行号是bundle文件中的行号,而且变量名也是编译过的,这样代码的阅读性就会下降,甚至根本找不到原因。而rn自己对离线sourcemap的支持非常不好(感觉很不科学啊,online的根本不需要sourcemap啊),甚至依赖包根本不能用。
所以我总结了一下离线sourcemap在android项目中的应用。
1.首先你要把sourcemap文件打包到android项目中,差不多像这样
2.其次,你的rn项目要依赖react-native-fs包,install出来以后把把下面android包中rnfs文件夹拷到你自己的android项目中当做你自己的操作类。大概像这样
3.往你项目的packageManager中添加rnfspackage,并在app启动的时候创建sourcemap文件在本地,像这样
4.在rn中创建错误收集handler
import ErrorUtils from'ErrorUtils';
import { alert } from'react-native';
import { initSourceMaps, getStackTrace } from'./SourceMapHandler';
import { nativeCallModuleWrapper } from'./NativeModuleWrappers/NativeCallModuleWrapper';
const setupErrorHandler =async (sourceMapBundleName)=> {
await initSourceMaps({sourceMapBundle: sourceMapBundleName,collapseInLine: true });
await (asyncfunction initUncaughtErrorHandler() {
const defaultGlobalHandler =ErrorUtils.getGlobalHandler();
ErrorUtils.setGlobalHandler(async (error, isFatal)=> {
try {
if (!__DEV__) {
error.stack = awaitgetStackTrace(error);
}
nativeCallModuleWrapper.reportCrash(error.message, error.stack);
} catch (ex) {
alert(`${ex.message}----Unable to setup global handler----${ex.stack}`);
}
if (__DEV__ && defaultGlobalHandler) {
defaultGlobalHandler(error, isFatal);
}
});
}());
};
export default setupErrorHandler;
5.创建错误收集handler需要用到的方法
import RNFS from'react-native-fs';
import SourceMap from"source-map";
import StackTrace from"stacktrace-js";
import ErrorStackParser from"error-stack-parser";
let sourceMapper = undefined;
let options = undefined;
/**
* Init Source mapper with options
* Required:
* @param {String} [opts.sourceMapBundle] - source map bundle, for example "main.jsbundle.map"
* Optional:
* @param {String} [opts.projectPath] - project path to remove from files path
* @param {Boolean} [opts.collapseInLine] — Will collapse all stack trace in one line, otherwise return lines array
*/
export constinitSourceMaps = asyncopts => {
if (!opts || !opts.sourceMapBundle) {
throw new Error('Please specify sourceMapBundle option parameter');
}
options = opts;
};
export constgetStackTrace = asyncerror => {
if (!options) {
throw new Error('Please firstly call initSourceMaps with options');
}
if (!sourceMapper) {
sourceMapper = awaitcreateSourceMapper();
}
try {
const minStackTrace = awaitfromError(error);
const stackTrace = minStackTrace.map(row=> {
const mapped =sourceMapper(row);
const source = mapped.source ||"";
const fileName = options.projectPath ? source.split(options.projectPath).pop() : source;
const functionName = mapped.name ||"unknown";
return {
fileName,
functionName,
lineNumber: mapped.line,
columnNumber: mapped.column,
position: `${functionName}@${fileName}:${mapped.line}:${mapped.column}`
};
});
return options.collapseInLine ? stackTrace.map(i=> i.position).join('\n') : stackTrace;
}
catch (error) {
alert(error.message);
throw error;
}
};
function _filtered(stackframes, filter) {
if (typeof filter ==='function') {
return stackframes.filter(filter);
}
return stackframes;
}
function fromError(error, opts){
var _options = {
filter: function(stackframe) {
// Filter out stackframes for this library by default
return (stackframe.functionName ||'').indexOf('StackTrace$$') ===-1 &&
(stackframe.functionName ||'').indexOf('ErrorStackParser$$') ===-1 &&
(stackframe.functionName ||'').indexOf('StackTraceGPS$$') ===-1 &&
(stackframe.functionName ||'').indexOf('StackGenerator$$') ===-1;
},
sourceCache: {}
};
opts = _merge(_options, opts);
//var gps = new StackTraceGPS(opts);
return newPromise(function(resolve) {
var stackframes =_filtered(ErrorStackParser.parse(error), opts.filter);
resolve(Promise.all(stackframes.map(function(sf) {
return newPromise(function(resolve) {
//function resolveOriginal() {
resolve(sf);
//}
//gps.pinpoint(sf).then(resolve, resolveOriginal)['catch'](resolveOriginal);
});
})));
}.bind(this));
}
function _merge(first, second) {
var target = {};
[first, second].forEach(function(obj) {
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
target[prop] = obj[prop];
}
}
return target;
});
return target;
}
const createSourceMapper =async () => {
RNFS.MainBundlePath="/storage/emulated/0/Android/data/com.test/cache"
const path = `${RNFS.MainBundlePath}/${options.sourceMapBundle}`;
try {
const fileExists = awaitRNFS.exists(path);
if (!fileExists) {
throw new Error(__DEV__ ?
'Unable to read source maps in DEV mode' :
`Unable to read source maps, possibly invalid sourceMapBundle file, please check that it exists here: ${RNFS.MainBundlePath}/${options.sourceMapBundle}`
);
}
const mapContents = awaitRNFS.readFile(path,'utf8');
const sourceMaps =JSON.parse(mapContents);
const mapConsumer =new SourceMap.SourceMapConsumer(sourceMaps);
return sourceMapper = row => {
return mapConsumer.originalPositionFor({
line: row.lineNumber,
column: row.columnNumber,
});
};
}
catch (error) {
throw error;
}
};
阅读全文
0 0
- 关于reactnatice android 集成离线sourcemap的
- sourcemap
- sourcemap
- 离线搭建 Android 集成开发环境
- android 关于webview离线观看
- 关于Android SDK使用离线包更新的说明
- 关于android 百度地图离线包的调用问题
- 关于android百度地图离线地图的使用
- 关于Android SDK使用离线包更新的说明
- 关于android 百度地图离线包的调用问题
- Android集成小米华为推送以及收不到离线消息的坑
- 关于webStorm设置less自动编译css和sourcemap问题
- 关于离线浏览器的记录
- 关于eclipse的离线汉化
- webpack sourcemap 选项多种模式的一些解释
- webpack sourcemap 选项多种模式的一些解释
- Ubuntu 14.04 Eclipse for Android 集成离线安装
- (二)ReactNatice命令总结
- 安卓动态权限管理
- C++实现序列的全排列
- 提高php代码质量36计
- 关于python的基础知识4--函数
- JavaScript中的各种宽高属性
- 关于reactnatice android 集成离线sourcemap的
- 深入分析Object.finalize方法的实现原理
- 自定义tableBarController
- 博客测试
- android下调试3G之自动拨号
- BZOJ——2342双倍回文
- linux下安装maven工具
- java创建.html或.text文件后中文乱码问题
- 字符设备、块设备、网络设备