在 iOS 和 Android 上运行 Go 代码( 二 )

创建我们的 iOS 应用程序使用 XCode , 我们可以创建一个简单的单页应用程序 。 我将使用 Swift UI , 但这与 UIKit 一样容易:
// ios/foobar/ContentView.swiftstruct ContentView: View {@State private var txt: String = ""var body: some View {VStack{TextField("", text: $txt).textFieldStyle(RoundedBorderTextFieldStyle())Button("Reverse"){// Reverse text here}Spacer()}.padding(.all, 15)}}在 Xcode 中 , 将新生成的 foo.a 和 foo.h 拖进我们的项目 。 为了使我们的 Swift 代码与我们的库互操作 , 我们需要创建一个桥接头文件:
// ios/foobar/foobar-Bridging-Header.h#import "foo.h"在 Xcode Build Settings 中 ,Swift Compiler - General 下 , 设置 Objective-C Bridging Header 为我们刚刚创建的文件: foobar/foobar-Bridging-Header.h。
我们还需要设置 Library Search Paths 为包括我们生成的头文件 foo.h 的目录 。 (当您将文件拖放到项目中时 , Xcode 可能已经为您完成了此操作) 。
现在我们可以从 Swift 调用函数 , 然后构建并运行:
// ios/foobar/ContentView.swiftButton("Reverse"){let str = reverse(UnsafeMutablePointer(mutating: (self.txt as NSString).utf8String))self.txt = String.init(cString: str!, encoding: .utf8)!// don't forget to release the memory to the C Stringstr?.deallocate()}
在 iOS 和 Android 上运行 Go 代码文章插图
libfoo ios 应用程序
创建 Android 应用程序使用 Android Studio , 我们将创建一个新的 Android 项目 。 从 Project Templates 中选择 Native C++, 这将创建一个带有 Empty Activity 的项目 , 该项目被配置为使用 Java Native Interface(JNI) 。 我们仍将选择 Kotlin 作为该项目的语言 。
创建一个简单的 Activity 后 , 加上 EditText 和 ,Button 两个控件 , 为应用创建基本功能:
// android/app/src/main/java/com/rogchap/foobar/MainActivity.ktclass MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)btn.setOnClickListener {txt.setText(reverse(txt.text.toString()))}}/*** A native method that is implemented by the 'native-lib' native library,* which is packaged with this application.*/private external fun reverse(str: String): Stringcompanion object {// Used to load the 'native-lib' library on application startup.init {System.loadLibrary("native-lib")}}}我们创建了(并调用)一个外部函数 reverse, 我们需要在 JNI (C++)实现:
// android/app/src/main/cpp/native-lib.cppextern "C" {jstringJava_com_rogchap_foobar_MainActivity_reverse(JNIEnv* env, jobject, jstring str) {// Reverse text herereturn str;}}JNI 代码必须遵循约定才能在本机 C++ 和 Kotlin(JVM)之间互操作 。
为 Android 构建在许多版本的 Android 和 NDK 中 , JNI 与外部库的工作方式已发生变化 。 当前(也是最简单的方法)是将输出的库放置到一个特殊的 jniLibs 文件夹中 , 该文件夹将复制到我们的最终 APK 文件中 。
与创建 Fat 二进制文件(就像我们在 iOS 中所做的那样)不同 , 我将每个体系结构放置在正确的文件夹中 。 同样 , 对于 JNI , 约定很重要 。
// go/MakefileANDROID_OUT=../android/app/src/main/jniLibsANDROID_SDK=$(HOME)/Library/Android/sdkNDK_BIN=$(ANDROID_SDK)/ndk/21.0.6113669/toolchains/llvm/prebuilt/darwin-x86_64/binandroid-armv7a: CGO_ENABLED=1 \ GOOS=android \ GOARCH=arm \ GOARM=7 \ CC=$(NDK_BIN)/armv7a-linux-androideabi21-clang \ go build -buildmode=c-shared -o $(ANDROID_OUT)/armeabi-v7a/libfoo.so ./cmd/libfooandroid-arm64: CGO_ENABLED=1 \ GOOS=android \ GOARCH=arm64 \ CC=$(NDK_BIN)/aarch64-linux-android21-clang \ go build -buildmode=c-shared -o $(ANDROID_OUT)/arm64-v8a/libfoo.so ./cmd/libfooandroid-x86: CGO_ENABLED=1 \ GOOS=android \ GOARCH=386 \ CC=$(NDK_BIN)/i686-linux-android21-clang \ go build -buildmode=c-shared -o $(ANDROID_OUT)/x86/libfoo.so ./cmd/libfooandroid-x86_64: CGO_ENABLED=1 \ GOOS=android \ GOARCH=amd64 \ CC=$(NDK_BIN)/x86_64-linux-android21-clang \ go build -buildmode=c-shared -o $(ANDROID_OUT)/x86_64/libfoo.so ./cmd/libfooandroid: android-armv7a android-arm64 android-x86 android-x86_64