Skip to content

Patch 处理

Patch 功能允许 VIP 用户修改和定制原生代码、资源文件,实现深度定制和快速修复。

什么是 Patch

Patch 是一种代码补丁机制,可以在不修改源码的情况下,对原生代码和资源进行修改。

使用场景

  • 🐛 快速修复原生代码 bug
  • 🎨 定制原生 UI 样式
  • 🔧 修改原生配置文件
  • 📝 替换原生资源文件
  • 🚀 临时功能调整
  • 🔄 版本兼容性处理

Patch 类型

1. 代码 Patch

修改 Java/Kotlin 或 Swift/Objective-C 代码。

支持的修改类型:

  • 替换整个类
  • 替换方法实现
  • 添加新方法
  • 修改方法调用

2. 资源 Patch

替换或新增资源文件。

支持的资源类型:

  • 图片资源
  • 布局文件
  • 字符串资源
  • 颜色值
  • 样式定义

3. 配置 Patch

修改配置文件。

可修改的配置:

  • AndroidManifest.xml
  • Info.plist
  • build.gradle
  • Podfile

创建 Patch

项目结构

在项目根目录创建 nativePatches 目录:

your-project/
└── nativePatches/
    ├── android/
    │   ├── code/
    │   ├── res/
    │   └── config/
    └── ios/
        ├── code/
        ├── res/
        └── config/

Android Patch

修改代码

创建文件 nativePatches/android/code/MainActivity.patch:

java
// 原始文件: io/dcloud/PandoraEntry.java
package io.dcloud;

import android.os.Bundle;

public class PandoraEntry extends io.dcloud.common.DHUniAppEntryActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // PATCH: 添加自定义逻辑
        initCustomFeature();
    }

    // PATCH: 新增方法
    private void initCustomFeature() {
        // 自定义初始化代码
        android.util.Log.d("Patch", "Custom feature initialized");
    }
}

修改资源

替换启动图:

nativePatches/android/res/
└── drawable-xxhdpi/
    └── splash.png  // 替换默认启动图

修改字符串资源 nativePatches/android/res/values/strings.xml:

xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- PATCH: 修改应用名称 -->
    <string name="app_name">我的定制应用</string>
</resources>

修改配置

修改 AndroidManifest.xml nativePatches/android/config/AndroidManifest.patch.xml:

xml
<?xml version="1.0" encoding="utf-8"?>
<manifest>
    <application>
        <!-- PATCH: 添加自定义 Activity -->
        <activity
            android:name=".CustomActivity"
            android:theme="@style/CustomTheme" />

        <!-- PATCH: 修改主题 -->
        <activity android:name="io.dcloud.PandoraEntry"
                  android:theme="@style/MyCustomTheme" />
    </application>

    <!-- PATCH: 添加权限 -->
    <uses-permission android:name="android.permission.BLUETOOTH" />
</manifest>

iOS Patch

修改代码

创建 nativePatches/ios/code/AppDelegate.patch.m:

objective-c
// 原始文件: AppDelegate.m
#import "AppDelegate.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    [super application:application didFinishLaunchingWithOptions:launchOptions];

    // PATCH: 添加自定义逻辑
    [self initCustomFeature];

    return YES;
}

// PATCH: 新增方法
- (void)initCustomFeature {
    NSLog(@"Custom feature initialized");
    // 自定义初始化代码
}

@end

修改资源

替换图标:

nativePatches/ios/res/
└── Assets.xcassets/
    └── AppIcon.appiconset/
        ├── icon-60@2x.png
        └── icon-60@3x.png

修改配置

修改 Info.plist nativePatches/ios/config/Info.patch.plist:

xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN">
<plist version="1.0">
<dict>
    <!-- PATCH: 添加 URL Scheme -->
    <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>myapp</string>
            </array>
        </dict>
    </array>

    <!-- PATCH: 修改相机权限说明 -->
    <key>NSCameraUsageDescription</key>
    <string>我们需要访问相机以拍摄照片</string>
</dict>
</plist>

Patch 配置

全局配置

创建 nativePatches/config.json:

json
{
  "version": "1.0.0",
  "description": "项目自定义 Patch",

  "android": {
    "enabled": true,
    "patches": [
      {
        "type": "code",
        "target": "io/dcloud/PandoraEntry.java",
        "source": "android/code/MainActivity.patch",
        "action": "replace"
      },
      {
        "type": "resource",
        "target": "res/drawable-xxhdpi/splash.png",
        "source": "android/res/drawable-xxhdpi/splash.png",
        "action": "replace"
      },
      {
        "type": "config",
        "target": "AndroidManifest.xml",
        "source": "android/config/AndroidManifest.patch.xml",
        "action": "merge"
      }
    ]
  },

  "ios": {
    "enabled": true,
    "patches": [
      {
        "type": "code",
        "target": "AppDelegate.m",
        "source": "ios/code/AppDelegate.patch.m",
        "action": "replace"
      },
      {
        "type": "config",
        "target": "Info.plist",
        "source": "ios/config/Info.patch.plist",
        "action": "merge"
      }
    ]
  }
}

Action 类型

  • replace: 完全替换目标文件
  • merge: 合并到目标文件
  • insert: 插入到指定位置
  • delete: 删除指定内容

高级用法

条件 Patch

根据条件应用不同的 Patch:

json
{
  "android": {
    "patches": [
      {
        "type": "code",
        "target": "MainActivity.java",
        "source": "android/code/MainActivity.patch",
        "condition": {
          "minSdkVersion": 28
        }
      }
    ]
  }
}

脚本 Patch

使用脚本动态生成 Patch:

json
{
  "android": {
    "patches": [
      {
        "type": "script",
        "script": "scripts/generate-patch.js",
        "args": ["--flavor", "production"]
      }
    ]
  }
}

脚本示例 scripts/generate-patch.js:

javascript
const fs = require('fs')

const flavor = process.argv[3] // 获取参数

// 根据参数生成不同的 Patch
const patchContent = `
// Generated for ${flavor}
public class Config {
    public static final String FLAVOR = "${flavor}";
}
`

fs.writeFileSync('generated/Config.java', patchContent)

正则替换

使用正则表达式替换:

json
{
  "android": {
    "patches": [
      {
        "type": "regex",
        "target": "build.gradle",
        "pattern": "versionCode \\d+",
        "replacement": "versionCode 100"
      }
    ]
  }
}

应用 Patch

自动应用

工具在打包时会自动应用配置的 Patch:

  1. 读取 nativePatches/config.json
  2. 根据配置查找 Patch 文件
  3. 按顺序应用 Patch
  4. 生成最终的原生代码

手动应用

在工具中:

  1. 打开"工具" > "Patch 管理"
  2. 查看可用的 Patch 列表
  3. 选择要应用的 Patch
  4. 点击"应用 Patch"

验证 Patch

应用后验证:

  1. 查看应用日志,确认 Patch 已应用
  2. 检查生成的代码/资源文件
  3. 运行应用测试功能

常见 Patch 示例

1. 修改应用主题色

Android - nativePatches/android/res/values/colors.xml:

xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#FF6B6B</color>
    <color name="colorPrimaryDark">#EE5A5A</color>
    <color name="colorAccent">#4ECDC4</color>
</resources>

iOS - nativePatches/ios/code/ThemeConfig.patch.swift:

swift
extension UIColor {
    static var appPrimary: UIColor {
        return UIColor(red: 1.0, green: 0.42, blue: 0.42, alpha: 1.0)
    }
}

2. 禁用横屏

Android - nativePatches/android/config/AndroidManifest.patch.xml:

xml
<manifest>
    <application>
        <activity android:name="io.dcloud.PandoraEntry"
                  android:screenOrientation="portrait" />
    </application>
</manifest>

iOS - nativePatches/ios/config/Info.patch.plist:

xml
<dict>
    <key>UISupportedInterfaceOrientations</key>
    <array>
        <string>UIInterfaceOrientationPortrait</string>
    </array>
</dict>

3. 自定义状态栏

Android - nativePatches/android/code/StatusBarPatch.java:

java
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // 设置状态栏透明
    Window window = getWindow();
    window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
    window.setStatusBarColor(Color.TRANSPARENT);
}

4. 修改网络请求超时

创建 Patch 修改网络配置:

json
{
  "android": {
    "patches": [
      {
        "type": "regex",
        "target": "io/dcloud/common/network/NetworkConfig.java",
        "pattern": "private static final int TIMEOUT = \\d+",
        "replacement": "private static final int TIMEOUT = 30000"
      }
    ]
  }
}

版本管理

Patch 版本

建议为 Patch 添加版本号:

nativePatches/
├── v1.0.0/
│   └── android/
├── v1.1.0/
│   └── android/
└── current -> v1.1.0/  # 软链接指向当前版本

升级处理

应用版本升级时:

  1. 备份当前 Patch
  2. 测试新版本兼容性
  3. 调整或重新创建 Patch
  4. 验证功能正常

调试 Patch

查看应用结果

打包后检查:

bash
# Android - 解压 APK
unzip app-release.apk -d output/

# 查看修改的文件
cat output/AndroidManifest.xml

日志输出

在 Patch 中添加日志:

java
// Android
android.util.Log.d("PATCH", "Patch applied successfully");

// iOS
NSLog(@"PATCH: Patch applied successfully");

真机测试

  1. 应用 Patch 后打包
  2. 安装到真机
  3. 运行并观察效果
  4. 查看日志输出

最佳实践

1. 文档化

为每个 Patch 添加注释:

java
/**
 * PATCH v1.0.0
 * 修改内容: 添加自定义初始化逻辑
 * 原因: 需要在应用启动时初始化第三方 SDK
 * 作者: zhangsan
 * 日期: 2024-01-01
 */
private void initCustomFeature() {
    // ...
}

2. 版本控制

将 Patch 纳入版本控制:

gitignore
# 不要忽略 nativePatches
!nativePatches/

3. 测试充分

  • 在多个设备上测试
  • 测试不同系统版本
  • 回归测试原有功能

4. 最小化修改

  • 只修改必要的部分
  • 避免大范围替换
  • 保持与原代码风格一致

常见问题

Patch 未生效

解决方案:

  1. 检查 config.json 配置正确
  2. 确认文件路径匹配
  3. 清理构建缓存重新打包
  4. 查看打包日志

Patch 冲突

问题: 多个 Patch 修改同一文件

解决方案:

  1. 合并 Patch 内容
  2. 调整 Patch 顺序
  3. 使用更精确的匹配规则

升级后 Patch 失效

解决方案:

  1. 检查目标代码是否改变
  2. 更新 Patch 内容
  3. 测试验证

安全提示

  • 🔒 不要在 Patch 中硬编码敏感信息
  • 🔐 Patch 文件也需要代码审查
  • 📝 记录所有 Patch 的变更历史
  • 🧪 充分测试避免引入安全漏洞

下一步

Released under the MIT License.