react-native 集成 FFmpeg 能力 - 使用 FFmpegKit(二)

相关文章:
react-native 集成 FFmpeg 能力 - 使用 FFmpegKit(一)
react-native 集成 FFmpeg 能力 - 使用 FFmpegKit(三)

这一篇主要记录对于 react-native 项目里,直接使用原生模块。

其实 react-native 能用起来,那就意味着原生的引入已经成功了。但是我以为和上一篇处理 react-native 库一样,在根目录的 ios 和 android 文件夹引入声明,相当于全局声明,自定义原生模块就可以直接使用了,但实际上不是,还需要在相应的自定义原生模块里再引入声明。

expo 项目有可以协助创建自定义原生模块的 create-expo-module。然后前提还是先把 ffmpegkit 的库下到本地来引入。

1. expo 项目 Android 引入

modules/native-module/android/build.gradle 加上:

dependencies {
    // 1. 直接引入 AAR,位置合理放置就行
    implementation files('libs/ffmpeg-kit-full-6.0-2.aar')
    // 2. 添加传递依赖(必须)
    implementation 'com.arthenica:smart-exception-java:0.2.1'
}

在代码里使用:

package expo.modules.settings

// 引入下面这三个
import com.arthenica.ffmpegkit.FFmpegKit
import com.arthenica.ffmpegkit.FFmpegSession
import com.arthenica.ffmpegkit.ReturnCode

import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition

class ExpoSettingsModule : Module() {
  override fun definition() = ModuleDefinition {
    Name("ExpoSettings")

    Function("getTheme") {
      return@Function "system"
    }
  }
}

2. expo 项目 IOS 引入

modules/native-module/ios/NativeModule.podspec 加上:

Pod::Spec.new do |s|
  s.name           = 'NativeModule'
  s.version        = '1.0.0'
  s.summary        = ''
  s.description    = ''
  s.author         = ''
  s.homepage       = 'https://docs.expo.dev/modules/'
  s.platforms      = {
    :ios => '15.1',
    :tvos => '15.1'
  }
  s.source         = { git: '' }
  s.static_framework = true

  s.dependency 'ExpoModulesCore'

  # Swift/Objective-C compatibility
  s.pod_target_xcconfig = {
    'DEFINES_MODULE' => 'YES',
  }

  s.source_files = "src/**/*.{h,m,mm,swift,hpp,cpp}"
  // 直接引入 xcframework, 位置合理放置就行
  s.vendored_frameworks = 'libs/*.xcframework'
end

在代码里使用:

import ExpoModulesCore

// 加上这句引用
import ffmpegkit

public class ExpoSettingsModule: Module {
  public func definition() -> ModuleDefinition {
    Name("ExpoSettings")

    Function("getTheme") { () -> String in
      "system"
    }
  }
}

下面两个只是尝试,然后记录一下,实际上用的上面 expo 项目

3. react-native 项目 IOS 引入, 使用 swift 语法

本质上差别不大,只是没有 expo 的辅助,改回 react-native 要求的语法。

modules/native-module/src/NativeModule.ts 改成:

// expo 改成 react-native 的模块引入方式
import { NativeModules } from 'react-native';
export const NewVideoEditor = NativeModules.NewVideoEditorModule;

podspec 文件和 expo 项目一样就行。

新增 modules/new-module/ios/src/NativeModule.m 文件:

#import <React/RCTBridgeModule.h>
#import <FFmpegKit/FFmpegKit.h>

@interface RCT_EXTERN_MODULE(NewVideoEditorModule, NSObject)

// 同步方法 - getName
RCT_EXTERN_METHOD(getName)

// 异步方法 - getFFmpegVersion
RCT_EXTERN_METHOD(getFFmpegVersion:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)

@end

新增 modules/new-module/ios/src/NativeModule.swift 文件:

import Foundation
import React
import ffmpegkit

@objc(NewVideoEditorModule)
class NewVideoEditorModule: NSObject, RCTBridgeModule {
    // MARK: - RCTBridgeModule
    static func moduleName() -> String! {
        return "NewVideoEditorModule"
    }
    static func requiresMainQueueSetup() -> Bool {
        return false
    }
    // MARK: - Exported Methods
    // 导出同步方法 - 使用 @objc 标记,React Native 会自动发现
    @objc
    func getName() -> String {
        return "NewVideoEditor-Name"
    }
    @objc
    func getFFmpegVersion(_ resolve: @escaping RCTPromiseResolveBlock,
                         rejecter reject: @escaping RCTPromiseRejectBlock) {
        let version = FFmpegKitConfig.getFFmpegVersion()
        resolve(version)
    }
}

上面的代码也是问 AI 问出来的,仅供参考,模块名和文件名需要按实际填写。这里的注意点还是原生 ios 的问题吧,据说 ios 提供给 react-native 的库是用 Objective-c 写的。所以在 react-native 里自定义原生 ios 模块里写 swift 也要包装成 Objective-c。

4. react-native 项目 IOS 引入, 使用 Objective-c 语法

参考 FFmpegKit 仓库 的写法就行,就是用 Objective-c 写的。
ios 的声明文件 podspec 文件和 ts 的导出文件 NativeModule.ts 和 swift 写法的一样就行。