gpt4 book ai didi

c++ - 在 Flutter 应用程序中使用来自 Android NDK 的 AssetManager 类

转载 作者:行者123 更新时间:2023-12-01 14:47:35 25 4
gpt4 key购买 nike

我一直在尝试使用 Android NDK 的 AssetManager我的 Flutter 应用程序中的类,适用于 Google Oboe , 访问音频文件。关注 this在 Oboe 存储库中的示例中,我了解到他们获得了 AssetManager像这样来自Java:

JNIEXPORT void JNICALL
Java_com_google_oboe_sample_rhythmgame_MainActivity_native_1onStart(JNIEnv *env, jobject instance,
jobject jAssetManager) {

AAssetManager *assetManager = AAssetManager_fromJava(env, jAssetManager);
if (assetManager == nullptr) {
LOGE("Could not obtain the AAssetManager");
return;
}

game = std::make_unique<Game>(*assetManager);
game->start();
}

基本上与论点 jAssetManager它们通过 JNI 接口(interface)从 Java 传递到 C++ 函数。现在我不使用 JNI,因为我使用的是 Flutter 和 Dart,而 Dart 中与 C++ 函数通信的方式是通过 dart:ffi ,但由于我可以创建 AssetManager 的唯一方法与 AAssetManager_fromJava(env, jAssetManager) ,我需要这两个参数,我找不到用 Flutter 和 Dart 替换的方法。

我做了一些研究,当我创建 Flutter FFI 插件时,显然 Dart 代码与 Kotlin 代码通信,然后调用 native C++ 函数。

这是我的 C++ 函数:
EXTERNC void *engine_create(void) {
AAssetManager *assetManager = AAssetManager_fromJava(env, jAssetManager); // ERROR: How do I get these?
if (assetManager == nullptr) {
LOGE("Could not obtain the AAssetManager");
return nullptr;
}

return new DSPAudioEngine(*assetManager);
}

这是该函数的 Dart 包装器:
import 'dart:ffi';
import 'dart:typed_data';

import 'package:ffi/ffi.dart';
import 'package:flutter/services.dart';

typedef oboe_engine_init = Pointer<Void> Function();
typedef OboeEngineInit = Pointer<Void> Function();

class FfiGoogleOboe {
static const MethodChannel _channel =
const MethodChannel('ffi_google_oboe');

static Future<String> get platformVersion async {
final String version = await _channel.invokeMethod('getPlatformVersion');
return version;
}

static FfiGoogleOboe _instance;

factory FfiGoogleOboe() {
if (_instance == null) {
_instance = FfiGoogleOboe._();
}
return _instance;
}


OboeEngineInit _engineInit;

FfiGoogleOboe._() {
final oboeLib = DynamicLibrary.open('libffi_google_oboe.so');

_engineInit = oboeLib
.lookup<NativeFunction<oboe_engine_init>>('engine_create')
.asFunction();
}

}

这是我在 FFI 插件实现中找到的 Kotlin 代码:
package g1_assd_2020.ffi_google_oboe

import androidx.annotation.NonNull;

import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry.Registrar
import android.content.res.AssetManager

/** FfiGoogleOboePlugin */
public class FfiGoogleOboePlugin: FlutterPlugin, MethodCallHandler {
/// The MethodChannel that will the communication between Flutter and native Android
///
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
/// when the Flutter Engine is detached from the Activity
private lateinit var channel : MethodChannel

override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.getFlutterEngine().getDartExecutor(), "ffi_google_oboe")
channel.setMethodCallHandler(this);
}

// This static function is optional and equivalent to onAttachedToEngine. It supports the old
// pre-Flutter-1.12 Android projects. You are encouraged to continue supporting
// plugin registration via this function while apps migrate to use the new Android APIs
// post-flutter-1.12 via https://flutter.dev/go/android-project-migration.
//
// It is encouraged to share logic between onAttachedToEngine and registerWith to keep
// them functionally equivalent. Only one of onAttachedToEngine or registerWith will be called
// depending on the user's project. onAttachedToEngine or registerWith must both be defined
// in the same class.
companion object {
@JvmStatic
fun registerWith(registrar: Registrar) {
val channel = MethodChannel(registrar.messenger(), "ffi_google_oboe")
channel.setMethodCallHandler(FfiGoogleOboePlugin())
}
}

override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
if (call.method == "getPlatformVersion") {
result.success("Android ${android.os.Build.VERSION.RELEASE}")
} else {
result.notImplemented()
}
}

override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
}

最后,这是 Oboe 的人们如何使用 JNI 和 Java 处理它的:
package com.google.oboe.sample.rhythmgame;

import android.content.Context;
import android.content.res.AssetManager;
import androidx.appcompat.app.AppCompatActivity;

import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import android.view.WindowManager;

public class MainActivity extends AppCompatActivity {

// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setDefaultStreamValues(this);
}

protected void onResume(){
super.onResume();
native_onStart(getAssets());
}

protected void onPause(){
super.onPause();
native_onStop();
}

static void setDefaultStreamValues(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){
AudioManager myAudioMgr = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
String sampleRateStr = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
int defaultSampleRate = Integer.parseInt(sampleRateStr);
String framesPerBurstStr = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
int defaultFramesPerBurst = Integer.parseInt(framesPerBurstStr);

native_setDefaultStreamValues(defaultSampleRate, defaultFramesPerBurst);
}
}

private native void native_onStart(AssetManager assetManager);
private native void native_onStop();
private static native void native_setDefaultStreamValues(int defaultSampleRate,
int defaultFramesPerBurst);
}

最佳答案

基本上,您需要将 AssetManager 引用从插件的 Kotlin 文件传递​​到 C++ 库。这个答案解释了如何让 Kotlin 文件调用 C++ 代码:Android: How to call ndk function from Kotlin?
您需要使用 methodChannel 调用来触发它。您可以从 flutterPluginBinding.applicationContext.assets 获取 onAttachedToEngine 方法中的 AssetManager 引用.
这是一个读取 C++ 库中 Assets 的 Flutter 插件示例:
https://github.com/mikeperri/ndk_asset_manager_example/commit/533d28b33c1d22f89028f89691f78e907bf19db3

关于c++ - 在 Flutter 应用程序中使用来自 Android NDK 的 AssetManager 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62398886/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com