集成基础:SDK集成方式与环境配置要点

咱们聊到Crash治理,第一步肯定是把SDK塞进项目里。这事儿看着简单,但我在实际项目中踩过的坑能绕办公室一圈。这章我就把Android、iOS、Web三端的集成套路给你捋一遍,外加那些环境配置里容易翻车的地方。

一、整体集成框架

先看一张图,帮你建立整体认识。SDK集成不是简单拷贝文件,它涉及引入依赖、初始化配置、权限申请、符号文件上传等环节。不同平台有各自的坑,但核心逻辑是通的。

Crash SDK 集成全流程 选择平台 Android (Java/Kotlin) iOS (ObjC/Swift) Web (JavaScript) 初始化配置 权限申请 符号文件上传 测试验证 Android 注意点 • 添加 jcenter/maven 仓库 • 配置 proguard 规则 • 网络权限声明 • 多 Flavor 适配 测试:手动触发崩溃 验证上报

二、Android SDK 集成实战

2.1 依赖引入方式

现在的Android项目多用Gradle。我习惯将SDK版本号统一写在项目级的ext块里,方便管理。直接在app/build.gradle中加入依赖:

dependencies {
    implementation 'com.example.crashtracker:crash-sdk:2.1.0'
    // 如果你需要NDK崩溃捕捉,加这个
    implementation 'com.example.crashtracker:crash-sdk-native:2.1.0'
}
小技巧:建议使用 implementation 而非 compile,因为 Android Gradle Plugin 3.0+ 已经移除了 compile 关键字。我在老旧项目里亲眼见过 compile 导致依赖冲突的情况。

2.2 混淆配置与权限

ProGuard/R8 会把SDK的类名混淆掉,crash堆栈就完全看不懂了。你得在proguard-rules.pro里保留SDK相关类:

-keep class com.example.crashtracker.** { *; }
-keep class * implements com.example.crashtracker.CrashHandler { *; }
-dontwarn com.example.crashtracker.**

权限方面,Android 6.0以上需要动态申请读写存储权限(如果你要写本地日志的话)。但说实话,我更建议直接用SDK默认的内存日志方案,避免和用户隐私政策冲突。我曾经有个项目为了写本地日志,被用户暗地里投诉了三次。

2.3 初始化时机

SDK初始化必须在Application.onCreate()里尽早执行,越早越好。你想想看,如果主线程上有个空指针崩溃发生在初始化之前,那就抓不到了。我一般把它放在 super.onCreate() 之后第一行:

public class MyApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        CrashSdk.init(this, new CrashConfig.Builder()
            .setAppId("your_app_id")
            .setDebug(BuildConfig.DEBUG)
            .build());
    }
}
警告:千万别在 ContentProvider 的 onCreate 里初始化。Android 多进程初始化顺序你猜不透,我见过有人在那里面初始化导致空指针——讽刺的是,自己的初始化代码反而产生了crash。

三、iOS SDK 集成要点

3.1 CocoaPods vs SPM

iOS现在主流是用CocoaPods或Swift Package Manager。我个人偏向SPM,因为Xcode原生支持,不需要额外装 Ruby 工具链。但如果你用的是ObjC混编项目,CocoaPods 可能更稳定。

用CocoaPods的话,Podfile里加一行:

pod 'CrashSDK', '~> 3.2.0'

用SPM的话,在Xcode里 File → Add Packages,输入仓库地址就行。注意选对版本规则,别用 "main" 分支,否则哪天SDK更新了你的编译就炸了。

3.2 初始化与符号化

iOS的初始化通常在AppDelegate的didFinishLaunchingWithOptions中:

import CrashSDK

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, 
                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        let config = CrashConfig(appId: "your_app_id")
        CrashSDK.start(with: config)
        return true
    }
}

符号化是个大坑。iOS崩溃堆栈里全是地址,必须上传dSYM文件才能还原成函数名。我建议用脚本自动上传:在 Build Phases 里加一个 Run Script,每次Archive后自动执行。

踩坑实录:我曾经忘记勾选 "Include Bitcode",导致dSYM文件和二进制不匹配,符号化完全失效。排查了两天才发现是Xcode 13以后Bitcode默认关闭了。所以,检查一下你的 Build Settings 里 Enable Bitcode 的状态。

四、Web SDK 集成方式

4.1 npm 安装 vs CDN

Web端最灵活。如果你的项目是React/Vue/Vite等现代框架,用npm安装:

npm install @crash-tracker/web-sdk --save

然后用导入方式初始化:

import { init } from '@crash-tracker/web-sdk';

init({
    appId: 'your_web_app_id',
    environment: process.env.NODE_ENV,
    // 是否监控白屏和资源加载错误
    monitorWhiteScreen: true
});

如果项目是传统JSP/ASP页面,直接用CDN script标签。但注意要放在页面顶部靠近head的位置,确保最早捕获错误。

4.2 跨域与SourceMap

Web端最头疼的是跨域脚本错误,堆栈显示 'Script error.' 什么信息都没有。解决方法是给script标签加 crossorigin 属性,并且CDN返回正确的 Access-Control-Allow-Origin 头。

另外,生产环境要上传SourceMap给SDK后台,这样压缩后的代码报错才能映射回原始源码。我通常用webpack插件自动上传:

new CrashSourceMapPlugin({
    url: 'https://crash.yourdomain.com/upload',
    appId: 'your_web_app_id'
})
建议:上传SourceMap后别忘了保护源码隐私。很多团队直接把完整源码传上去,这等于暴露了逻辑。我习惯只上传文件名和行号的映射关系,去掉源代码内容。

五、环境配置通用要点

不管哪个平台,有几个配置逃不掉。我整理了一张表,方便你对照检查。

配置项说明常见错误
AppKey / AppId SDK用于标识你的应用,从后台获取 复制粘贴多了空格,调试半天看不出
Debug模式开关 开发时设为true,能看到SDK日志;线上必须false 有人忘了关,导致用户端也在打印敏感日志
渠道标识 区分不同发布渠道(应用宝、华为、App Store) 渠道名用了中文,导致后台统计乱码
上报策略 实时/间隔/仅WiFi上传等 默认实时可能导致用户流量暴增
符号文件上传 Android的mapping.txt / iOS的dSYM / Web的SourceMap 忘记上传,crash堆栈全是地址

嗯,有一点需要特别提醒:测试环境不要和线上用同一个AppId。你会把开发阶段的试错crash和线上真实crash混在一起,根本没法分析。我一般建三个项目:Dev、Staging、Production,各配不同的AppId。

六、验证集成是否成功

集成完了,怎么确认SDK真的工作了?不能等到用户出问题才发现没上报吧。

  • Android:写一个按钮,点击后执行 Integer.parseInt(null) 或 throw new RuntimeException("test")。看后台有没有收到这条crash。
  • iOS:用 NSArray *arr = @[]; arr[1] 触发越界。记得只在Debug包做测试,别带到Release里。
  • Web:直接在控制台执行 undefined.xxx 触发TypeError,等几秒看后台日志。
重要:测试crash上报时,一定要关闭Xcode或Android Studio的调试器。因为调试器会拦截所有信号量,crash不会被SDK捕捉到。我刚开始学的时候在调试模式测了一整天,一直收不到crash,差点怀疑人生。

最后说一句:集成本身不复杂,复杂的是那些你意想不到的边界情况——比如用户手机空间不足、网络被屏蔽、权限被系统强杀。这些我们后面章节会细讲。先把基础集成跑通,才算真正迈出Crash治理第一步。