編譯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