前言
繼上一次發(fā)布的 Flutter 直接調(diào)用so動(dòng)態(tài)庫,或調(diào)用C/C++源文件內(nèi)函數(shù) 內(nèi)容,最終我選擇了第二種方式,直接把整個(gè) Native C++ 的項(xiàng)目源代碼放進(jìn)了 Flutter 工程里編譯(放在iOS的目錄是因?yàn)樗恢С肿远x源碼路徑,Android是可以的)。這樣的好處是 Android 和 iOS 兩個(gè)平臺(tái)都不需要分別再去寫原生代碼調(diào)用 .so 文件,也不用關(guān)注動(dòng)態(tài)庫平臺(tái),而且改動(dòng)更方便。
編譯時(shí) Android 側(cè)會(huì)生成指定平臺(tái)的 .so 文件(Gradle里配置),iOS 側(cè)會(huì)生成指定平臺(tái)的 .a 文件(XCode里配置)
背景
Flutter 的項(xiàng)目里需要調(diào)用 C++ 進(jìn)行 APDU
指令的操作和傳輸,APDU 也就是一串 16 進(jìn)制編碼的字符串,也就是說 出入?yún)?/code> 需要傳輸
非短整型的值
。實(shí)際傳輸需要根據(jù) C++ 端的定義去使用 Flutter 端的數(shù)據(jù)類型。
一、代碼部分
1. 分析底層定義函數(shù)的出入?yún)⒄页鲇成漕愋?/h4>
例如:C++ 定義了如下函數(shù)
extern "C" short apduProcess(uint8_t *apdu, uint8_t *response, uint8_t *len) {
... apdu & response 業(yè)務(wù)處理
return 0;
}
我們的關(guān)鍵點(diǎn)就是分析 C++ 定義的 出入?yún)?/strong> 的數(shù)據(jù)類型映射,參考 Dart - C 數(shù)據(jù)類型映射表 可以得出結(jié)論:
- 函數(shù)出參 用于返回函數(shù)執(zhí)行結(jié)果,使用的
short
類型,對應(yīng) Dart NativeType 的Int16
類型; - 函數(shù)入?yún)⒂腥齻€(gè) 用于數(shù)據(jù)的輸入和輸出,使用的
uint8_t
類型,對應(yīng) Dart NativeType 的Uint8
類型,需要注意的是三個(gè)參數(shù)均為指針類型,由于 FFI 無法直接傳輸數(shù)組,因此需要需要自行開辟空間進(jìn)行存取,類型為 使用Pointer<Uint8>
;
于是 Flutter 端得到了如下函數(shù):
typedef NativeFunc =
Int16 Function(Pointer<Uint8>, Pointer<Uint8>, Pointer<Uint8>);
typedef FFIFunc =
int Function(Pointer<Uint8>, Pointer<Uint8>, Pointer<Uint8>);
2. 調(diào)用函數(shù)
final func = _library.lookupFunction<NativeFunc, FFIFunc>('apduProcess');
// 初始化三個(gè)指針參數(shù)
final apdu = [0x00, 0xA4, 0x04, ...];
final inputApduPointer = calloc<Uint8>(apdu.length);
inputApduPointer.asTypedList(apdu.length).setAll(0, apdu);
final respApduPointer = calloc<Uint8>(100);
final respLenPointer = calloc<Uint8>(2);
// 調(diào)用函數(shù)
final result = func(inputApduPointer, respApduPointer, respLenPointer);
// 需要在指針釋放之前把response值取出來
String respApduStr = '';
for (var index = 0; index < respLenPointer.value; index++) {
// 由于我傳入的內(nèi)容是 16 進(jìn)制字符串,所以需要 .toRadixString(16).padLeft(2, '0')
respApduStr += respApduPointer.elementAt(index).value.toRadixString(16).padLeft(2, '0');
}
// 釋放申請的內(nèi)存空間
calloc.free(inputApduPointer);
calloc.free(respApduPointer);
calloc.free(respLenPointer);
3. 結(jié)論
遍歷 respApduPointer.elementAt(index).value
即可將正確的值取出
而這兩種方式拿到的值是不對的:文章來源:http://www.zghlxwxcb.cn/news/detail-758799.html
// 錯(cuò)誤方式 1
respApduPointer.cast<Utf8>().toDartString()
// 錯(cuò)誤方式 2
respApduPointer.asTypedList(xxx).map((e) => e.toRadixString(16).padLeft(2, '0')).join('')
二、分析一下我走的彎路
重點(diǎn)看 final respApduPointer = calloc<Uint8>(100);
這個(gè)變量,實(shí)際上它是給到 C++ 存數(shù)據(jù)的,所以我們?nèi)≈登耙残枰卺尫艃?nèi)存之前。它的類型是:Pointer<Uint8>
,實(shí)際上也就這幾個(gè)方法和屬性:
這個(gè)變量實(shí)際存的是 C++ 的 uint8_t *response
,是一個(gè)指針數(shù)組(由n個(gè)指針類型元素組成的一個(gè)數(shù)組),而不是一個(gè)數(shù)組指針(數(shù)組變量是一個(gè)指針類型),上面列舉的錯(cuò)誤方式其實(shí)操作的是指針變量,而 elementAt
取到的才是指針數(shù)組里的單個(gè)元素的指針文章來源地址http://www.zghlxwxcb.cn/news/detail-758799.html
到了這里,關(guān)于Flutter Dart FFI Pointer<Uint8>類型如何轉(zhuǎn)成數(shù)組或String的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!