flutter進(jìn)階(2)Android Studio ndk編譯帶預(yù)編譯庫(kù)的C++&dart調(diào)用

編譯protbuf.so,protoc,前期準(zhǔn)備鏈接:http://www.itdecent.cn/p/6e8c30a4cbaf

生成好了預(yù)編譯庫(kù)之后,我們有自己的使用需求,把它編寫成了文件之后,再通過(guò)ndk把整個(gè)項(xiàng)目編譯成一個(gè).so庫(kù)供dart前端調(diào)用。

調(diào)用分為下面幾個(gè)步驟:
1.通過(guò)protoc將.proto文件生成pb.cc和pb.h
2.撰寫一個(gè)Android.mk和Application.mk封裝預(yù)編譯庫(kù)和自己寫的函數(shù)
3.寫一個(gè)dart文件把這個(gè)庫(kù)里面的函數(shù)調(diào)用出來(lái),供主函數(shù)調(diào)用

1.通過(guò)protoc將.proto文件生成pb.cc和pb.h

上篇文章當(dāng)中寫了如何使用vs2019對(duì)protobuf進(jìn)行編譯生成protoc,這個(gè)時(shí)候我們找到protoc的位置,然后復(fù)制路徑,打開:此電腦-高級(jí)系統(tǒng)設(shè)置-環(huán)境變量-PATH,把剛剛的路徑復(fù)制進(jìn)去。

接下來(lái),在我們的項(xiàng)目當(dāng)中建立一個(gè)簡(jiǎn)單的person.proto文件

syntax = "proto3";
package prophet;

message Person {
    int32 id = 1;
    string name = 2;
    string email = 3;
}

然后打開cmd命令行,進(jìn)入到你現(xiàn)在這個(gè)文件夾的路徑,可以通過(guò)右擊Android studio的文件夾來(lái)copy path。

使用命令:protoc --cpp_out=./ person.proto

就會(huì)生成person.pb.cc和person.pb.h了。

2.撰寫Android.mk和Application.mk封裝預(yù)編譯庫(kù)和C++文件

我們之前已經(jīng)通過(guò)ndk編譯過(guò)了protobuf.so(記住一定是要按照我上一篇文章編譯的protobuf.so如果用cmake或者其他版本application.mk編譯的會(huì)不兼容的)

在build-app-intermediates-ndkbuild-... 里面把protobuf.so找到,然后拷貝出來(lái),放到android-app-src-main-xxx-prebuilt文件夾底下,這是我的文件夾目錄層級(jí):

然后再將protobuf源碼包當(dāng)中的src/google文件夾拷貝到這個(gè)prebuilt-protobuf文件夾底下,因?yàn)榫幾g這個(gè)庫(kù)的時(shí)候會(huì)用到一些頭文件,需要在源碼里面找(這就是windows很不友好的原因...)。

我們先寫一個(gè)例程,在這個(gè)目錄下創(chuàng)建一個(gè)test.cpp文件,調(diào)用一下Person當(dāng)中的函數(shù)。

#include<stdio.h>
#include"person.pb.h"
extern "C"{
//__attribute__((visibility("default"))) __attribute__((used)
int32_t native_add(int32_t x, int32_t y) { return x + y; }

double double_add(double x, double y) { return x + y; }

int test()
{
   prophet::Person person;
   person.set_id(101);
   person.set_name("yvhqbat");
   person.set_email("yvhbat@126.com");
   //int32_t a = adb();
    return person.id();
}}

在這里調(diào)用了Person類,同時(shí)給他設(shè)定了一些屬性,然后調(diào)用了id這個(gè)屬性,返回類型為int。

extern "C"具體怎么用其實(shí)我沒(méi)有什么經(jīng)驗(yàn),有興趣的可以看最下面的參考鏈接。

接下來(lái)撰寫Android.mk和Application.mk

Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := protobuf
LOCAL_SRC_FILES := $(LOCAL_PATH)/prebuilt/libprotobuf.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/prebuilt/protobuf
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := test
LOCAL_CFLAGS := -std=c++11 -fexceptions -frtti
LOCAL_SRC_FILES :=  $(LOCAL_PATH)/test.cpp            \
                    $(LOCAL_PATH)/person.pb.cc        \
                    $(LOCAL_PATH)/person.pb.h         \
                    #./prebuilt/libprotobuf.so
LOCAL_SHARED_LIBRARIES := protobuf

include $(BUILD_SHARED_LIBRARY)
#include $(BUILD_STATIC_LIBRARY)

Application.mk

APP_MODULES      := test
APP_PLATFORM     := android-26
APP_ABI          := arm64-v8a
APP_STL := c++_static
APP_OPTIM        := debug

這里面的ABI版本一定要是自己設(shè)備支持的,我現(xiàn)在用的這個(gè)支持的是arm64-v8a,有的設(shè)備應(yīng)該是支持armeabi-v7a,如果不匹配有可能會(huì)出現(xiàn)skipping incompatible的錯(cuò)誤。

arm64-v8a是華為平板適用的架構(gòu),如果你是電腦模擬器打開的話,可以用x86_64的架構(gòu),不過(guò)記得把之前protobuf編譯時(shí)候用到的Application也改了,這些都必須是統(tǒng)一的才行。

這個(gè)時(shí)候,運(yùn)行一下,成功的話,應(yīng)該能在build里面找到生成的庫(kù)了,。

3.C++例程&dart調(diào)用

接下來(lái)就是前端調(diào)用的部分了,寫一個(gè)dart程序來(lái)調(diào)用這個(gè)C++當(dāng)中的函數(shù)。

這里有一點(diǎn)要注意:dart只能調(diào)用以extern "C"寫的函數(shù),C++寫的函數(shù)不支持。

在根目錄下的lib目錄當(dāng)中新建一個(gè).dart文件。

import 'dart:async';

import 'package:flutter/services.dart';

import 'dart:ffi'; // For FFI
import 'dart:io'; // For Platform.isX

final DynamicLibrary nativeLib = Platform.isAndroid
    ? DynamicLibrary.open('libtest.so')
    : DynamicLibrary.process();

final int Function() test =
nativeLib
    .lookup<NativeFunction<Int32 Function()>>("test")
    .asFunction();

class Native {
  static const MethodChannel _channel =
  const MethodChannel('test');

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

使用dart的ffi庫(kù)來(lái)調(diào)用這個(gè)libtest.so,然后通過(guò)lookup來(lái)找到其中的function。

最后在main函數(shù)里加上調(diào)用這個(gè)函數(shù)的命令就可以了。

效果展示:

參考鏈接

Android.mk和Application.mk講解 推薦指數(shù)※※※※※

extern “C”講解 https://blog.csdn.net/T146lLa128XX0x/article/details/81713862

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容