flutter進(jìn)階(1)ndk編譯protobuf&作為預(yù)編譯庫(kù)使用

大家查資料還是得去官網(wǎng),官網(wǎng)上還是挺全的,不要浪費(fèi)時(shí)間看別人的教程。官網(wǎng)鏈接在最底下參考鏈接里

今天要講的這個(gè)過(guò)程是一個(gè)我大概花了一周時(shí)間才解決的問(wèn)題:在windows10系統(tǒng)當(dāng)中如何把protobuf庫(kù)使用C++的寫法在Android Studio項(xiàng)目當(dāng)中進(jìn)行調(diào)用

網(wǎng)上大部分的教程都是關(guān)于如何用ndk編譯protobuf的,或者只是單獨(dú)如何將一個(gè)普通的c++編譯成.so文件鏈接到Android Studio項(xiàng)目上的(如果這是linux系統(tǒng)就簡(jiǎn)單地多了...)。

在這里首先有一個(gè)坑要注意:ndk編譯跟cmake編譯是不兼容的

其實(shí)android studio可以直接支持protobuf的java編譯,在plugin里有protobuf-support下載然后gradle里配置一下就可以了,但是我不會(huì)寫java,而且這個(gè)插件下載要翻墻,所以就沒(méi)有選擇這個(gè)方案。

ndk編譯protobuf總共分為以下幾步:
1.通過(guò)cmake_gui生成vs2019所需文件
2.vs2019編譯protobuf生成protoc
3.使用ndk編譯protobuf生成.so文件
4.自己寫一個(gè)proto文件,然后調(diào)用protobuf包當(dāng)中的protoc來(lái)生成文件

1.通過(guò)cmake_gui生成protoc

首先下載cmake和protobuf的源碼,下載地址:

cmake:https://cmake.org/download/選binary distribution里面的msi文件,可以直接運(yùn)行的。

protobuf https://github.com/protocolbuffers/protobuf下載下來(lái)解壓

安裝好cmake之后,打開cmake_gui這個(gè)可執(zhí)行文件,然后把要源碼的地址和要輸出文件的地址選好(最好就放在protobuf這個(gè)層級(jí)底下)。

這個(gè)時(shí)候點(diǎn)configure,它會(huì)讓你選擇哪個(gè)編譯版本,這個(gè)時(shí)候依據(jù)你選擇的編譯器進(jìn)行更改,比如通用的vs,我下載的是2019版本,那就選擇vs2019,然后點(diǎn)擊確定。

這個(gè)時(shí)候一般有可能會(huì)出現(xiàn)一個(gè)問(wèn)題,因?yàn)槲覀冊(cè)谙螺d源碼的時(shí)候是不帶test項(xiàng)目的,所以會(huì)缺一些文件,但是對(duì)本體protobuf沒(méi)有影響,可以改變產(chǎn)生cmake文件的選項(xiàng)來(lái)略過(guò)這個(gè)問(wèn)題。

這樣就生成好了vs2019編譯所需的cmake文件和sln文件了。

2.vs2019編譯protobuf

首先,下載vs2019:vs2019(不太清楚需不需要翻墻,選擇community社區(qū)版下載安裝。

按照默認(rèn)配置安裝就可以了,安裝好了之后運(yùn)行,選擇打開項(xiàng)目或解決方案,點(diǎn)擊到之前生成好的文件夾當(dāng)中,選擇后綴為.sln的文件進(jìn)行打開(這代表是vs2019的一個(gè)項(xiàng)目)。

然后再點(diǎn)擊這個(gè)按鈕就可以進(jìn)行編譯了。

在編譯好了之后進(jìn)到那個(gè)文件夾當(dāng)中,進(jìn)入Debug就可以看到protoc這個(gè)文件了,這個(gè)文件我們之后會(huì)用到。

3.使用ndk編譯protobuf生成.so文件

有些人可能會(huì)覺(jué)得很奇怪,之前不是編譯過(guò)了,怎么還要編譯。在vs2019里面編譯出
來(lái)的是dll庫(kù),也是動(dòng)態(tài)鏈接庫(kù),在安卓上用不了,所以我們需要使用在android studio上的ndk插件來(lái)進(jìn)行編譯生成.so的庫(kù)。

首先我們要新建一個(gè)flutter項(xiàng)目,如果有疑問(wèn)可以看flutter中文網(wǎng)

我們將protobuf/src/下面的google復(fù)制,放在android-app-src-main-jni目錄下。

首先更改android-app-build.gradle,在android的層級(jí)下加入下面的程序。

    externalNativeBuild {
        ndkBuild {
            // Tells Gradle to put outputs from external native
            // builds in the path specified below.
            path './src/main/jni/Android.mk'
            buildStagingDirectory "./outputs/ndk-build"
        }
    }

這個(gè)代表使用原生的編譯方式,調(diào)用這個(gè)Android.mk,調(diào)用這個(gè)的同時(shí)也會(huì)調(diào)用跟他同一級(jí)目錄的Application.mk。

接下來(lái)編寫這個(gè)Android.mk和Application.mk,這些文件的詳情參考鏈接里有。
Andorid.mk


LOCAL_PATH := $(call my-dir)
 
include $(CLEAR_VARS)
 
LOCAL_MODULE := protobuf
LOCAL_CFLAGS := -std=c++11 -fexceptions -frtti
LOCAL_MODULE_FILENAME := libprotobuf
LOCAL_SRC_FILES :=  google/protobuf/stubs/bytestream.cc                          \
                     google/protobuf/stubs/bytestream.h                           \
                     google/protobuf/stubs/common.cc                              \
                     google/protobuf/stubs/hash.h                                 \
                     google/protobuf/stubs/int128.cc                              \
                     google/protobuf/stubs/int128.h                               \
                     google/protobuf/io/io_win32.cc                               \
                     google/protobuf/stubs/map_util.h                             \
                     google/protobuf/stubs/mathutil.h                             \
                     google/protobuf/stubs/status.cc                              \
                     google/protobuf/stubs/status.h                               \
                     google/protobuf/stubs/status_macros.h                        \
                     google/protobuf/stubs/statusor.cc                            \
                     google/protobuf/stubs/statusor.h                             \
                     google/protobuf/stubs/stringpiece.cc                         \
                     google/protobuf/stubs/stringpiece.h                          \
                     google/protobuf/stubs/stringprintf.cc                        \
                     google/protobuf/stubs/stringprintf.h                         \
                     google/protobuf/stubs/structurally_valid.cc                  \
                     google/protobuf/stubs/strutil.cc                             \
                     google/protobuf/stubs/time.cc                                \
                     google/protobuf/stubs/time.h                                 \
                     google/protobuf/any_lite.cc                                  \
                     google/protobuf/arena.cc                                     \
                     google/protobuf/extension_set.cc                             \
                     google/protobuf/generated_enum_util.cc                       \
                     google/protobuf/generated_message_util.cc                    \
                     google/protobuf/generated_message_table_driven_lite.h        \
                     google/protobuf/generated_message_table_driven_lite.cc       \
                     google/protobuf/implicit_weak_message.cc                     \
                     google/protobuf/message_lite.cc                              \
                     google/protobuf/parse_context.cc                             \
                     google/protobuf/repeated_field.cc                            \
                     google/protobuf/wire_format_lite.cc                          \
                     google/protobuf/io/coded_stream.cc                           \
                     google/protobuf/io/strtod.cc                                 \
                     google/protobuf/io/zero_copy_stream.cc                       \
                     google/protobuf/io/zero_copy_stream_impl.cc                  \
                     google/protobuf/io/zero_copy_stream_impl_lite.cc             \
                      google/protobuf/any.pb.cc                                    \
                       google/protobuf/api.pb.cc                                    \
                       google/protobuf/any.cc                                       \
                       google/protobuf/descriptor.cc                                \
                       google/protobuf/descriptor_database.cc                       \
                       google/protobuf/descriptor.pb.cc                             \
                       google/protobuf/duration.pb.cc                               \
                       google/protobuf/dynamic_message.cc                           \
                       google/protobuf/empty.pb.cc                                  \
                       google/protobuf/extension_set_heavy.cc                       \
                       google/protobuf/field_mask.pb.cc                             \
                       google/protobuf/generated_message_reflection.cc              \
                       google/protobuf/generated_message_table_driven_lite.h        \
                       google/protobuf/generated_message_table_driven.cc            \
                       google/protobuf/map_field.cc                                 \
                       google/protobuf/message.cc                                   \
                       google/protobuf/reflection_internal.h                        \
                       google/protobuf/reflection_ops.cc                            \
                       google/protobuf/service.cc                                   \
                       google/protobuf/source_context.pb.cc                         \
                       google/protobuf/struct.pb.cc                                 \
                       google/protobuf/stubs/substitute.cc                          \
                       google/protobuf/stubs/substitute.h                           \
                       google/protobuf/text_format.cc                               \
                       google/protobuf/timestamp.pb.cc                              \
                       google/protobuf/type.pb.cc                                   \
                       google/protobuf/unknown_field_set.cc                         \
                       google/protobuf/wire_format.cc                               \
                       google/protobuf/wrappers.pb.cc                               \
                       google/protobuf/io/gzip_stream.cc                            \
                       google/protobuf/io/printer.cc                                \
                       google/protobuf/io/tokenizer.cc                              \
                       google/protobuf/compiler/importer.cc                         \
                       google/protobuf/compiler/parser.cc                           \
                       google/protobuf/util/delimited_message_util.cc               \
                       google/protobuf/util/field_comparator.cc                     \
                       google/protobuf/util/field_mask_util.cc                      \
                       google/protobuf/util/internal/constants.h                    \
                       google/protobuf/util/internal/datapiece.cc                   \
                       google/protobuf/util/internal/datapiece.h                    \
                       google/protobuf/util/internal/default_value_objectwriter.cc  \
                       google/protobuf/util/internal/default_value_objectwriter.h   \
                       google/protobuf/util/internal/error_listener.cc              \
                       google/protobuf/util/internal/error_listener.h               \
                       google/protobuf/util/internal/expecting_objectwriter.h       \
                       google/protobuf/util/internal/field_mask_utility.cc          \
                       google/protobuf/util/internal/field_mask_utility.h           \
                       google/protobuf/util/internal/json_escaping.cc               \
                       google/protobuf/util/internal/json_escaping.h                \
                       google/protobuf/util/internal/json_objectwriter.cc           \
                       google/protobuf/util/internal/json_objectwriter.h            \
                       google/protobuf/util/internal/json_stream_parser.cc          \
                       google/protobuf/util/internal/json_stream_parser.h           \
                       google/protobuf/util/internal/location_tracker.h             \
                       google/protobuf/util/internal/mock_error_listener.h          \
                       google/protobuf/util/internal/object_location_tracker.h      \
                       google/protobuf/util/internal/object_source.h                \
                       google/protobuf/util/internal/object_writer.cc               \
                       google/protobuf/util/internal/object_writer.h                \
                       google/protobuf/util/internal/protostream_objectsource.cc    \
                       google/protobuf/util/internal/protostream_objectsource.h     \
                       google/protobuf/util/internal/protostream_objectwriter.cc    \
                       google/protobuf/util/internal/protostream_objectwriter.h     \
                       google/protobuf/util/internal/proto_writer.cc                \
                       google/protobuf/util/internal/proto_writer.h                 \
                       google/protobuf/util/internal/structured_objectwriter.h      \
                       google/protobuf/util/internal/type_info.cc                   \
                       google/protobuf/util/internal/type_info.h                    \
                       google/protobuf/util/internal/type_info_test_helper.cc       \
                       google/protobuf/util/internal/type_info_test_helper.h        \
                       google/protobuf/util/internal/utility.cc                     \
                       google/protobuf/util/internal/utility.h                      \
                       google/protobuf/util/json_util.cc                            \
                       google/protobuf/util/message_differencer.cc                  \
                       google/protobuf/util/time_util.cc                            \
                       google/protobuf/util/type_resolver_util.cc
 
 
LOCAL_EXPORT_C_INCLUDES :=
LOCAL_EXPORT_LDLIBS :=
 
LOCAL_C_INCLUDES := $(LOCAL_PATH) \
$(LOCAL_PATH)/src
 
LOCAL_LDLIBS := -llog -lz
 
include $(BUILD_SHARED_LIBRARY)
#include $(BUILD_STATIC_LIBRARY)

Application.mk

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

這里面主要就是編譯這個(gè)包所需要包含的源文件,我編譯的是整個(gè)protobuf,所以比較多。

具體要編譯的這些文件在protobuf/src/Makefile.am當(dāng)中,你可以根據(jù)自己源碼版本進(jìn)行更改,如果你想編譯protobuf-lite,就去找libprotobuf_lite_la_SOURCES的變量定義復(fù)制過(guò)來(lái)就可以了。

然后生成一個(gè)AVD的模擬器或者是外接一個(gè)android設(shè)備,就可以編譯了。

編譯之后,我們點(diǎn)擊停止(不點(diǎn)擊停止,build不會(huì)刷新),然后在build(注意是根目錄下的build)/app/intermediates/ndkbuild點(diǎn)到底就可以找到libprotobuf.so就說(shuō)明編譯成功了。

到這里protobuf的ndk編譯就完成了,如果想用其他方式調(diào)用這個(gè)protobuf.so也是可以直接調(diào)用的了。

結(jié)語(yǔ)

flutter其實(shí)還是一個(gè)應(yīng)用起來(lái)有一些難度的大前端框架,它的學(xué)習(xí)曲線比較陡峭,需要懂的東西也比較多。由于這個(gè)框架不是非常的穩(wěn)定,經(jīng)常在更新,網(wǎng)上很多可以搜出來(lái)的解決方法有可能已經(jīng)過(guò)時(shí)了,這個(gè)時(shí)候就需要通過(guò)一些經(jīng)驗(yàn)來(lái)自己解決問(wèn)題。

在編寫一個(gè)app的時(shí)候,往往需要前后端結(jié)合,dart雖然是一個(gè)比較通用的語(yǔ)言,但是還是不如C++在后端上的應(yīng)用廣泛,所以如何將寫好的C++庫(kù)鏈接到flutter的項(xiàng)目上確實(shí)是一個(gè)比較重要的過(guò)程。

參考資料

flutter調(diào)用C++ https://blog.csdn.net/guawazi123321/article/details/105099443
這篇文章有一些問(wèn)題,但是具有借鑒意義,它生成出來(lái)的.so文件不能被dart的dynamicLibrary調(diào)用,這個(gè)我們后面會(huì)講到。

深入解讀Cmake http://www.itdecent.cn/p/089b458ab8d5 我們其實(shí)沒(méi)有用到cmake,有興趣的可以自己看一下。

Android studio ndk編譯protobuf生成C++的.so鏈接庫(kù)https://blog.csdn.net/niuben127/article/details/78738671

Android 官網(wǎng)關(guān)于android當(dāng)中安裝ndk的介紹 https://developer.android.com/studio/projects/install-ndk

Android官網(wǎng)關(guān)于使用ndk及預(yù)編譯庫(kù)配置的介紹&Android.mk和Application.mk詳解
https://developer.android.google.cn/ndk/guides/android_mk

最后編輯于
?著作權(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)容