好,接着往下看吧。
环境准备
一台Linux 64的机器
一个带有AndroidStudioIDE的开发机器
因为环境配置实在复杂,所以我们引入的docker。
docker pull codeskyblue/docker-goandroid
docker run --rm -ti codeskyblue/docker-goandroid bash
cd example; echo "view example projects
docker起来之后,什么就都配置好了,NDK啦,java啦,GO的环境变量了,等等,并且还预装了vim,gradle,tmux,git,syncthing,svn
开始写代码
写代码之前,先约定下目录结构
go的代码都放在src/golib下,编译使用makebash编译脚本,看下这个文件树
|-- appiml
|-- buildgradle
|-- libs/armeabi-v7a # go编译生成的so文件
| `-- libgojniso
|-- maingo_tmpl # 一个模板文件,先不用管它
|-- makebash # 编译脚本,用来生成so和Java代码
`-- src
|-- golib
| |-- hi
| | |-- go_hi�0�2�0�2�0�2 # 自动生成的代码
| | | `-- go_higo
| | `-- higo # 需要编写的代码
| `-- maingo
`-- main
|-- AndroidManifestxml
|-- java
| |-- go # 自动生成的代码
| | |-- Gojava
| | |-- Seqjava
| | `-- hi
| | `-- Hijava
| `-- me/shengxiang/gohello # 主要的逻辑代码
| `-- MainActivityjava
`-- res
我已经写了一个例子,先直接搞下来
编译下,试试行不行(就算不行问题应该也不大,因为大问题都被我消灭了)
cd GoHello/app
/makebash
/gradlew build
一切顺利的话在build/outputs/apk下应该可以看到app-debugapk这个文件。(剧透下,这个文件只有800多K)
编译好的我放到qiniu上了,可以点击下载看看
下面可以尝试改改,我抛砖引玉说下
打开higo这个文件
higo的内容,比较简单,我们写Go代码主要就是这部分
// Package hi provides a function for saying hello
package hi
import "fmt"
func Hello(name string) {
fmtPrintf("Hello, %s!\n", name)
return "(Go)World"
}
文件末尾添加下面这行代码
func Welcome(name string) string {
return fmtSprintf("Welcome %s to the go world", name)
}
使用/makebash重新编译下
打开MainActivityjava 修改下OnClickListener事件
buttonsetOnClickListener(new ViewOnClickListener() {
@Override
public void onClick(View v) {
String message = HiWelcome("yourname");
ToastmakeText(MainActivitythis, message, ToastLENGTH_LONG)show();
}
});
编译运行下,把生成的apk安装到手机上试试。
原理解读(有兴趣的接着看)
首先说下gobind这个工具。
go_hi/go_higo这个文件时通过gobind这个工具生成的,用来配合一个简单的程序,生成so文件
// go_higo
package go_hi
import (
"golangorg/x/mobile/bind/seq"
"example/hi"
)
func proxy_Hello(out, in seqBuffer) {
param_name := inReadUTF16()
hiHello(param_name)
}
func init() {
seqRegister("hi", 1, proxy_Hello)
}
这个简单的程序内容是这样的
// maingo
package main
import (
"golangorg/x/mobile/app"
_ "golangorg/x/mobile/bind/java"
_ "example/hi/go_hi"
)
func main() {
appRun(appCallbacks{})
}
src/MyActivityjava文件内容是这样的
import
import goGo; // 引入Go这个包
import gohiHi; // gobind生成的代码
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
superonCreate(savedInstanceState);
Goinit(getApplicationContext()); // 初始化两个线程
HiHello("world");
}
}
其中有一句Goinit()这里再看goGo这个包是什么样子的
public final class Go {
// init loads libgojniso and starts the runtime
public static void init(Context context) {
判断该函数是否该执行的代码 -- 省略 --
SystemloadLibrary("gojni"); // gojni需要这句
new Thread("GoMain") {
public void run() {
Gorun(); // run()是一个native方法
}
}start();
GowaitForRun(); // 这个也是一个native方法
// 这部分可以理解为,启动了一个后台线程不断的接收结果到缓存中。
new Thread("GoReceive") {
public void run() { Seqreceive(); }
}start();
}
private static boolean running = false;
private static native void run();
private static native void waitForRun();
}
MyActivityjava中还有段代码是 HiHello("world");,打开Hijava路径在src/go/hi/Hijava,这个文件也是gobind生成的,是用来给java方便的调用so文件
// Hijava
// File is generated by gobind Do not edit
package gohi;
import goSeq;
public abstract class Hi {
private Hi() {} // uninstantiable
public static void Hello(String name) {
goSeq _in = new goSeq();
goSeq _out = new goSeq();
_inwriteUTF16(name);
Seqsend(DESCRIPTOR, CALL_Hello, _in, _out); // 下面接着说
}
private static final int CALL_Hello = 1;
private static final String DESCRIPTOR = "hi";
}
Seqsend这部分实际上最终调用的是一段go代码
func Send(descriptor string, code int, req Cuint8_t, reqlen Csize_t, res Cuint8_t, reslen Csize_t) {
fn := seqRegistry[descriptor][code]
in := new(seqBuffer)
if reqlen > 0 {
inData = ([maxSliceLen]byte)(unsafePointer(req))[:reqlen]
}
out := new(seqBuffer)
fn(out, in)
seqToBuf(res, reslen, out)
}
转载仅供参考,版权属于原作者。祝你愉快,哦
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)