这次我们来看一个在安卓端实现高性能目标检测的纯 Native 方案。项目标题“安卓里程碑!纯Native实现Yolo26 QNN+TFLITE!”已经点明了核心:它不是一个依赖复杂框架的 Demo,而是通过纯 C/C++(Native)代码,将最新的 YOLOv26 模型与高通 QNN(Qualcomm Neural Network SDK)和谷歌 TFLite(TensorFlow Lite)推理引擎结合,旨在为安卓应用提供高效、低延迟的本地 AI 能力。对于需要在移动端集成实时目标检测功能的开发者来说,这直接关系到应用能否流畅运行、耗电是否可控以及模型精度能否保障。
这个项目的重点不是概念多复杂,而是它解决了安卓端 AI 部署的几个关键痛点:脱离沉重的 Python 环境、追求极致的推理速度和兼容广泛的硬件设备。通过纯 Native 实现,它避免了 JNI 调用 Java 层带来的额外开销,并同时支持高通的 DSP/NPU(通过 QNN)和通用的 CPU/GPU(通过 TFLite),让开发者能根据设备能力选择最优后端。本文将带你快速了解这个方案的核心能力、环境搭建步骤、模型转换流程,并完成一个基础的功能验证。如果你关心如何在安卓 App 中集成最新的 YOLO 模型,并希望获得接近原生的性能,这篇文章值得你继续往下看。
1. 核心能力速览
在深入细节之前,我们先通过一个表格快速把握这个方案的全貌和关键参数。
| 能力项 | 说明 |
|---|---|
| 项目类型 | 安卓本地 AI 推理库 / 目标检测集成方案 |
| 核心技术 | YOLOv26 模型 + 纯 C/C++ Native 层实现 |
| 推理引擎 | QNN (Qualcomm Neural Network SDK)与TFLite (TensorFlow Lite)双后端支持 |
| 主要功能 | 静态图片目标检测、实时摄像头流目标检测、自定义模型集成 |
| 推荐硬件 | 搭载高通骁龙芯片(支持 Hexagon DSP/NPU)的安卓设备;也支持其他安卓设备的 CPU/GPU 推理 |
| 性能特点 | 纯 Native 实现,减少 JNI 开销;可针对 QNN 进行算子优化,提升在骁龙平台上的能效比 |
| 输出格式 | 检测框 (Bounding Box)、类别标签 (Class Label)、置信度分数 (Confidence Score) |
| 适合场景 | 需要离线、实时目标检测的安卓应用,如安防监控、AR 应用、工业质检、移动端自动化工具等 |
| 使用边界 | 需自行准备符合业务需求的 YOLOv26 模型文件;涉及人脸等敏感信息检测时,务必确保符合隐私法规并获得用户授权。 |
2. 适用场景与使用边界
2.1 谁适合使用这个方案?
这个纯 Native 的 YOLOv26 方案主要面向以下几类开发者:
- 安卓应用开发者:需要在 App 中集成高性能、低延迟的目标检测功能,例如开发具有物体识别功能的相机应用、AR 游戏或智能工具。
- 嵌入式 AI 工程师:针对搭载高通骁龙平台的边缘设备(如智能摄像头、机器人、车载设备)进行算法部署和优化。
- 算法部署工程师:研究如何将最新的 YOLO 系列模型高效地部署到移动端,并对比不同推理后端(QNN vs TFLite)的性能差异。
2.2 能解决什么问题?
- 性能瓶颈:传统的通过 JNI 调用 Python 或使用封装厚重的框架进行推理的方式,往往存在初始化慢、内存占用高、推理延迟大的问题。本方案通过纯 Native C++ 实现核心推理流程,最大限度地减少了运行时开销。
- 硬件加速利用不足:许多安卓设备,特别是中高端机型,配备了强大的 DSP 或 NPU。本方案通过集成 QNN SDK,能够充分调用高通 Hexagon 处理器的算力,实现比纯 CPU 推理高数倍的速度和更低的功耗。
- 模型更新滞后:YOLOv26 作为该系列的最新演进,在精度和效率上可能有新的改进。此方案提供了将前沿模型落地到移动端的快速通道。
2.3 不适合什么场景?
- 快速原型验证:如果你只是想快速验证一个目标检测想法,而不追求极致的端侧性能,使用 TFLite 官方 Demo 或 MediaPipe 等更高层级的框架可能更快捷。
- 非安卓平台:此方案专为安卓系统设计,无法直接用于 iOS、Linux 或其他操作系统。
- 需要频繁更换模型结构:每次更换模型(如从 YOLOv26 换为 YOLOv11),都需要重新进行模型转换、算子适配(特别是对于 QNN)和 Native 代码的集成测试,有一定工作量。
2.4 合规与安全边界
至关重要:在集成此类视觉 AI 能力时,必须严格遵守法律法规和平台政策。
- 隐私保护:如果检测目标涉及人脸、车牌等个人敏感信息,必须在应用中明确告知用户并获得其明确授权。检测数据应在设备端处理,避免未经用户同意上传至服务器。
- 版权与授权:确保你使用的 YOLOv26 模型权重是合法获取的,并遵守其对应的开源协议(如 GPL、MIT)。
- 使用场景合规:不得将本技术用于非法监控、侵犯他人隐私或任何违反公序良俗的用途。
3. 环境准备与前置条件
开始集成前,请确保你的开发环境满足以下要求。这是后续所有步骤的基础。
3.1 硬件与操作系统
- 开发机:一台运行 Windows、macOS 或 Linux 的电脑,用于模型转换和编译。
- 测试设备:一部安卓手机或开发板。强烈建议使用搭载高通骁龙芯片的设备(如骁龙 8 系列、7 系列),以便测试 QNN 后端的高性能模式。其他安卓设备也可用于测试 TFLite 的 CPU/GPU 后端。
- 设备要求:安卓系统版本建议在Android 8.0 (API Level 26)及以上,以确保对 Neural Networks API (NNAPI) 和现代 C++ 运行库有良好支持。
3.2 软件开发环境
- Android Studio:最新稳定版,用于创建和管理 Native C++ 项目。
- Android NDK:版本建议在r21+。在 Android Studio 的 SDK Manager 中下载并配置。
- CMake:3.18 或更高版本。通常随 Android Studio 或 NDK 一起安装。
- Python 环境:用于模型转换和预处理脚本。推荐 Python 3.7-3.9。
- 模型文件:你需要准备训练好的 YOLOv26 模型权重文件(通常是
.pt格式)和对应的模型配置文件(.yaml)。
3.3 关键 SDK 下载
- TensorFlow Lite:推理引擎和模型转换工具。可以通过 Python pip 安装:
pip install tensorflow # 或者仅安装 TFLite 转换工具 # pip install tf-nightly - QNN SDK:这是本方案发挥骁龙平台性能优势的关键。你需要从高通开发者网络(Qualcomm Developer Network)注册并下载Qualcomm Neural Processing SDK。下载后,将其解压到本地目录,记下路径(例如
D:\Qualcomm\QNN)。请注意,QNN SDK 的下载和使用需要遵守高通的许可协议。
4. 模型转换:从 PyTorch 到 TFLite/QNN
这是部署流程中最核心的技术环节。YOLOv26 原生模型通常为 PyTorch 格式,需要转换为移动端可用的格式。
4.1 转换为 TFLite 格式
TFLite 格式通用性最强,是很好的起点和后备方案。
- 导出为 ONNX:首先将 PyTorch (.pt) 模型转换为 ONNX 格式。这通常使用 PyTorch 自带的
torch.onnx.export函数完成。你需要准备好一个示例输入张量(dummy input)。import torch model = torch.load('yolov26.pt', map_location='cpu')['model'].float() model.eval() dummy_input = torch.randn(1, 3, 640, 640) # 假设输入为 640x640 RGB 图像 torch.onnx.export(model, dummy_input, "yolov26.onnx", input_names=['images'], output_names=['output0'], # 根据模型实际输出名调整 opset_version=12, dynamic_axes={'images': {0: 'batch'}}) - ONNX 转 TFLite:使用
onnx-tf或tf2onnx工具将 ONNX 模型转换为 TensorFlow SavedModel,然后再用 TFLite Converter 转换。import tensorflow as tf # 假设已通过其他工具得到 saved_model 目录 converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir) converter.optimizations = [tf.lite.Optimize.DEFAULT] # 可尝试量化以减小模型体积、提升速度(可能损失精度) # converter.representative_dataset = representative_data_gen # converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8] # converter.inference_input_type = tf.uint8 # converter.inference_output_type = tf.uint8 tflite_model = converter.convert() with open('yolov26.tflite', 'wb') as f: f.write(tflite_model)
4.2 转换为 QNN 格式
要发挥骁龙 DSP/NPU 性能,需将模型转换为 QNN 的.bin和.cpp文件。
- 安装 QNN 工具链:使用下载的 QNN SDK 中的转换工具。通常路径为
[QNN_SDK]/bin/[host-system]/qnn-model-converter或qnn-onnx-converter。 - 执行转换:在终端或命令行中运行转换命令。这是一个示例:
此命令会生成# 假设在 Windows 下,且 QNN 工具在系统 PATH 中 qnn-onnx-converter --input_network yolov26.onnx --input_dim images 1,3,640,640 --output_path yolov26_qnn --cpp_define_file model.cppyolov26_qnn.bin(模型数据)和model.cpp(包含模型图的 C++ 源文件)。你需要将这两个文件集成到你的安卓 Native 项目中。
重要提示:YOLO 模型中的某些算子(如SiLU激活函数、特定尺度的Upsample)可能不被 QNN 原生支持。转换时可能会报错或需要你编写自定义算子(Custom Op)。这是移动端部署高级模型常见的挑战,需要根据错误信息查阅 QNN 文档进行算子替换或实现。
5. 安卓项目集成与 Native 层实现
现在我们开始在 Android Studio 中创建一个支持 Native 开发的项目,并集成推理引擎。
5.1 创建 Native C++ 项目
- 打开 Android Studio,新建一个项目,模板选择“Native C++”。
- 在配置项目时,
C++ Standard选择“C++17”或更高,Exceptions Support和Runtime Type Information建议勾选。 - 项目创建后,你会看到
cpp目录,其中包含CMakeLists.txt和native-lib.cpp文件。
5.2 配置 CMakeLists.txt
这是构建系统的核心。你需要在此文件中链接 TFLite 和 QNN 的库。
cmake_minimum_required(VERSION 3.18.1) project("yolov26_demo") # 设置 TFLite 库的路径(假设你已下载预编译库或通过其他方式获取) set(TFLITE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/tflite) add_library(lib_tflite STATIC IMPORTED) set_target_properties(lib_tflite PROPERTIES IMPORTED_LOCATION ${TFLITE_DIR}/libtensorflowlite.so) # 设置 QNN 库的路径 set(QNN_SDK_PATH “D:/Qualcomm/QNN”) # 替换为你的实际路径 include_directories(${QNN_SDK_PATH}/include) add_library(lib_qnn STATIC IMPORTED) set_target_properties(lib_qnn PROPERTIES IMPORTED_LOCATION ${QNN_SDK_PATH}/lib/aarch64-android/libQnnHtp.so) # 以 HTP 后端为例 add_library(yolov26_demo SHARED native-lib.cpp # 添加你的其他 C++ 源文件,例如 model.cpp (QNN 模型图) model.cpp ) find_library(log-lib log) target_link_libraries(yolov26_demo android lib_tflite lib_qnn ${log-lib} )注意:你需要提前准备好 TFLite 的 Android 预编译库(可从官方 GitHub 发布页下载),并将 QNN SDK 中的对应库文件(如libQnnHtp.so,libQnnCpu.so)和头文件放入项目指定目录。
5.3 实现 Native 推理逻辑
在native-lib.cpp或新建的类中,你需要实现:
- 模型加载与初始化:编写两个初始化函数,分别用于加载 TFLite 模型文件(
.tflite)和 QNN 模型文件(.bin和.cpp中定义的图)。 - 预处理:将安卓
Bitmap或相机YUV数据转换为模型所需的输入张量(例如,归一化、调整大小到 640x640、转换为NHWC格式)。 - 推理执行:根据用户选择或设备能力,调用 TFLite Interpreter 或 QNN 的 Runtime API 执行推理。
- 后处理:解析模型输出的张量,应用非极大值抑制(NMS)算法,过滤掉低置信度的检测框,并将坐标转换回原始图像尺寸。
以下是 TFLite 后端推理的极简示例框架:
#include <jni.h> #include <android/bitmap.h> #include “tensorflow/lite/interpreter.h“ #include “tensorflow/lite/model.h“ #include “tensorflow/lite/kernels/register.h“ class TFLiteDetector { private: std::unique_ptr<tflite::Interpreter> interpreter; public: bool loadModel(const char* model_path) { model = tflite::FlatBufferModel::BuildFromFile(model_path); tflite::ops::builtin::BuiltinOpResolver resolver; tflite::InterpreterBuilder(*model, resolver)(&interpreter); interpreter->AllocateTensors(); return true; } std::vector<Detection> detect(uint8_t* input_data) { // 获取输入输出张量指针 float* input = interpreter->typed_input_tensor<float>(0); // ... 将 input_data 预处理并填充到 input ... interpreter->Invoke(); float* output = interpreter->typed_output_tensor<float>(0); // ... 解析 output,进行 NMS 后处理 ... return detections; } }; extern “C“ JNIEXPORT jlong JNICALL Java_com_example_yolov26_MainActivity_initTFLite(JNIEnv* env, jobject /* this */, jstring modelPath) { const char* path = env->GetStringUTFChars(modelPath, nullptr); auto* detector = new TFLiteDetector(); detector->loadModel(path); env->ReleaseStringUTFChars(modelPath, path); return reinterpret_cast<jlong>(detector); }QNN 后端的实现更为复杂,涉及QnnContext、QnnGraph的创建和执行,需要参考 QNN SDK 的示例代码。
6. Java/Kotlin 层封装与调用
Native 层完成后,需要在 Java/Kotlin 层提供易用的接口。
6.1 创建 JNI 接口类
package com.example.yolov26; public class YOLOv26Native { // 加载 native 库 static { System.loadLibrary(“yolov26_demo“); } // 初始化 TFLite 检测器 public native long initTFLiteDetector(String modelPath); // 初始化 QNN 检测器 public native long initQNNDetector(String modelBinPath, String modelCppPath); // 执行检测 (传入 Bitmap) public native DetectionResult[] detectBitmap(long detectorPtr, Bitmap bitmap, boolean useQNN); // 执行检测 (传入 NV21 字节数据,适用于相机预览) public native DetectionResult[] detectNV21(long detectorPtr, byte[] nv21Data, int width, int height, int rotation, boolean useQNN); // 释放检测器 public native void releaseDetector(long detectorPtr); }DetectionResult是一个自定义的 Java 类,包含rect(RectF),labelId,labelName,confidence等字段。
6.2 在 Activity 中使用
在 MainActivity 中,你可以根据设备芯片类型动态选择后端,并处理相机数据或图片。
class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding private var nativeDetectorPtr: Long = 0 private var useQNN: Boolean = false // 根据设备判断 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) // 判断是否支持 QNN (例如,检查是否为高通设备) useQNN = isQualcommDevice() val modelPath = if (useQNN) { // 从 assets 复制 .bin 和 .cpp 到文件目录 copyAssetsToFiles(“yolov26_qnn.bin“) filesDir.absolutePath + “/yolov26_qnn.bin“ } else { copyAssetsToFiles(“yolov26.tflite“) filesDir.absolutePath + “/yolov26.tflite“ } // 初始化 Native 检测器 nativeDetectorPtr = if (useQNN) { YOLOv26Native.initQNNDetector(modelPath, getModelCppPath()) } else { YOLOv26Native.initTFLiteDetector(modelPath) } // 设置相机回调或按钮点击事件 binding.cameraView.setLifecycleOwner(this) binding.cameraView.addFrameProcessor { frame -> val nv21Data = frame.image.toNV21() // 转换为 NV21 val results = YOLOv26Native.detectNV21(nativeDetectorPtr, nv21Data, frame.size.width, frame.size.height, frame.rotation, useQNN) runOnUiThread { drawDetections(results) } } } override fun onDestroy() { YOLOv26Native.releaseDetector(nativeDetectorPtr) super.onDestroy() } }7. 功能测试与效果验证
集成完成后,必须进行系统性的测试来验证功能、性能和稳定性。
7.1 基础图片检测测试
目的:验证模型能否正确加载并执行单张图片推理。
- 准备素材:在 App 的
assets文件夹或 SD 卡中放置几张包含典型目标(如人、车、狗)的测试图片。 - 操作步骤:在 App 中实现一个按钮,点击后从图库选择或加载固定测试图片,调用
detectBitmap方法。 - 预期结果:图片上应绘制出正确的检测框和标签。可以对比同一张图片在 PC 端 PyTorch 模型下的推理结果,确保类别和位置基本一致。
- 成功标准:模型成功加载,推理过程不崩溃,能输出合理的检测结果。
7.2 实时摄像头流测试
目的:验证在实时视频流上的性能和稳定性,这是移动端应用的核心场景。
- 操作步骤:启动 App 的相机预览功能,在每一帧回调中调用
detectNV21方法。 - 观察指标:
- 帧率 (FPS):在界面显示实时推理帧率。目标是在保证精度的前提下,达到可交互的帧率(例如 >15 FPS)。
- 延迟:从摄像头捕获一帧到绘制出检测结果之间的时间差。
- CPU/GPU/DSP 占用:使用 Android Profiler 或
adb shell top命令观察推理线程的 CPU 占用。对于 QNN 后端,可以观察 Hexagon DSP 的负载。 - 内存占用:观察 Native 堆内存是否平稳,避免内存泄漏。
- 成功标准:应用运行稳定,无卡顿、无闪退,帧率和延迟满足业务需求,资源占用在合理范围内。
7.3 双后端对比测试
目的:量化 QNN 后端相比 TFLite (CPU/GPU/NNAPI) 带来的性能提升。
- 测试方法:在同一台高通设备上,分别使用 QNN 后端和 TFLite 后端(可设置不同的 Delegate,如
NNAPI、GPU)运行相同的测试集(例如一段 30 秒的视频)。 - 记录数据:记录平均 FPS、平均每帧推理耗时、功耗(如果设备支持)或电池温度变化。
- 结果分析:通常,QNN 在骁龙平台上利用 DSP/NPU 能获得显著的能效比优势,推理速度更快,CPU 占用更低,从而更省电。
8. 性能优化与资源管理
移动端部署,性能优化是永恒的主题。
8.1 模型优化
- 量化:将模型从 FP32 转换为 INT8 或 FP16,可以大幅减少模型体积、降低内存带宽需求、提升推理速度。TFLite 和 QNN 都支持量化。但需注意,量化可能带来精度损失,必须用测试集验证。
- 剪枝与蒸馏:在模型训练阶段或训练后,通过剪枝移除不重要的权重,或通过知识蒸馏训练一个更小的学生模型,从而获得更轻量的模型。
8.2 推理过程优化
- 输入分辨率:YOLOv26 默认输入可能是 640x640。如果业务场景对远处小目标要求不高,可以尝试降低到 480x480 甚至 320x320,能成倍减少计算量。
- 批处理:虽然实时摄像头通常是单帧处理,但对于图片批量处理场景,Native 代码应支持批处理以提升吞吐。
- 线程池:在 Native 层使用线程池来处理预处理、推理、后处理等任务,避免阻塞 UI 线程或相机线程。
8.3 内存与功耗管理
- 模型单例:确保在整个 App 生命周期内,模型只加载一次,并通过指针或全局变量共享。
- 及时释放:在
onPause或检测器不用时,及时释放 Native 层分配的大块内存(如输入输出张量缓存)。 - 动态频率选择:对于持续推理的场景(如持续录像分析),可以根据温度或电量情况,动态调整推理频率(如从 30FPS 降到 10FPS)或切换后端(从 QNN 切换到低功耗的 CPU 模式)。
9. 常见问题与排查方法
在集成过程中,你可能会遇到以下问题:
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
App 启动崩溃,日志显示java.lang.UnsatisfiedLinkError | Native 库未正确加载或符号未找到。 | 检查System.loadLibrary的库名是否与CMakeLists.txt中add_library的目标名一致。检查是否所有依赖的 .so 文件(如 libQnnHtp.so)都打包进了 APK。 | 使用adb logcat查看详细崩溃栈。确保.so文件在jniLibs对应 ABI 目录下。检查CMakeLists.txt链接是否正确。 |
| 模型转换失败,QNN 转换器报错“Unsupported operator” | YOLOv26 模型中包含 QNN 不支持的算子。 | 查看转换日志,确认具体是哪个算子不支持。 | 1. 尝试更新到最新版 QNN SDK。2. 在模型训练或导出 ONNX 前,尝试用 QNN 支持的算子替换(如将SiLU替换为Swish的等价组合)。3. 为不支持的算子实现 QNN 自定义算子(较高难度)。 |
| 推理结果完全错误或为空 | 输入数据预处理错误,或输出后处理逻辑错误。 | 1. 对比 Native 预处理和 Python 端预处理每个步骤的输出(如归一化值、维度顺序)。2. 打印 Native 推理输出的原始张量值,与 PC 端推理结果对比。 | 仔细核对预处理步骤:颜色通道顺序(RGB/BGR)、归一化系数(/255.0 或 /127.5 -1)、输入张量维度(NCHW/NHWC)。确保后处理中解析输出维度的逻辑与模型定义完全匹配。 |
| 使用 QNN 后端时性能反而比 TFLite CPU 还慢 | 1. 模型未在 DSP/NPU 上运行,而是 fallback 到了 CPU。2. 模型包含大量不适合 DSP 的算子。 | 1. 查看 QNN 初始化日志,确认运行时后端是否为HTP(Hexagon Tensor Processor)。2. 使用 QNN 的性能分析工具。 | 1. 确保设备 Hexagon DSP 驱动正常。2. 检查模型转换日志,看是否有算子不支持 HTP 而回退到 CPU。优化模型结构或实现自定义算子。 |
| 相机预览时检测框抖动或延迟大 | 1. 每帧处理时间过长。2. UI 绘制与推理线程竞争。 | 测量detectNV21方法的平均耗时。使用 Systrace 工具观察 UI 线程和推理线程的调度。 | 1. 优化模型(量化、降低分辨率)。2. 在 Native 层使用双缓冲或队列,避免推理阻塞相机回调。3. 降低预览帧率或检测帧率。 |
| 长时间运行后 App 闪退或设备发热严重 | 内存泄漏或计算资源持续高占用。 | 使用 Android Studio Profiler 监控 Native 内存和 CPU 使用情况。检查是否有对象未释放。 | 1. 确保每次推理后,临时分配的内存被正确释放。2. 实现简单的“冷却”机制,在设备温度过高时暂停或降低推理频率。 |
10. 总结与下一步
这个“纯 Native 实现 Yolo26 QNN+TFLITE”的方案,为安卓端部署高性能、低延迟的目标检测功能提供了一条值得深入探索的路径。它的核心价值在于剥离了不必要的中间层,让开发者能更直接地控制推理管线,并充分利用硬件加速潜力。对于追求极致性能的移动应用来说,这种深度集成的思路是必要的。
最值得你优先尝试的,是完成TFLite 后端的完整集成链路:从模型转换、项目配置、Native 层实现到 Java 层调用。这一步能让你快速验证整个流程的可行性。之后,再挑战QNN 后端的集成与性能调优,这将是发挥骁龙设备全部AI算力的关键。
最容易踩的坑主要集中在模型转换和预处理/后处理对齐上。务必使用同一张测试图片,在 PC 端原始模型和移动端转换后的模型上对比输出,确保每一个数值细节都一致。
完成基础功能后,你可以继续深入以下几个方向:
- 多模型支持:将架构抽象化,使其能轻松切换不同的 YOLO 版本或其他视觉模型。
- 算法功能扩展:在检测基础上,增加跟踪(Tracking)、计数、行为分析等功能。
- 工程化完善:添加模型热更新、A/B 测试、线上性能监控等生产级特性。
- 探索其他硬件后端:除了 QNN,还可以尝试集成 MediaTek NeuroPilot、华为 HiAI 等针对其他芯片平台的 SDK,提升方案的普适性。
将先进的 AI 模型塞进小小的手机里并流畅运行,始终是一个充满挑战又极具成就感的过程。希望这篇梳理能为你提供一个清晰的起点和避坑指南。建议收藏本文,在集成过程中逐步对照实践。