iOS
build
.go ──gomobile bind -target ios──▶ Golibpkg.xcframework   machine code
.mm .cc .h ──clang──▶ .o ──link (with the xcframework)──▶ .app   machine code
.app ──package──▶ .ipa
run
Obj-C++ ──direct call──▶ Go
one process, one kind of memory, all unmanaged, no boundary crossed
Android
build
.go ──go build -buildmode=c-shared──▶ libgolib.so   machine code
.cc .h ──clang──▶ .o ──link──▶ libchrome.so   machine code
.java ──javac──▶ .class ──d8──▶ classes.dex   bytecode, for ART
(not used) .go ──gomobile bind -target android──▶ .aar = classes.jar + jni/*.so
.so + .dex + resources ──package──▶ .apk
install
dex2oat compiles part of classes.dex AOT into .oat   machine code
run, cgo path (used)
C++ in libchrome.so ──dlsym──▶ Go in libgolib.so
both sides are machine code, unmanaged, no boundary crossed
run, gomobile path (not used)
C++ (unmanaged) ──JNI──▶ Java (on ART, managed) ──JNI──▶ Go (unmanaged)
crosses the boundary twice; each JNI hop copies the arguments into the Java heap