如何Golang開發Android應用(for golang1.4)

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

轉載隨意:文章出處 http://shengxiang.me/article/38/write-android-program-with-golang.html

Golang是一門強型別程式設計語言,2009年推出,在今年2014年,開始支援android的開發了。

環境配置好複雜,我不得不嘮叨幾句。

需要下載golang1.4rc版,下載ndk,然後編譯。然後用go get 下載gobind這個工具,然後,將寫好的代碼用gobind轉化下,然後使用特殊的編譯命令,將代碼編譯成.so檔案,將產生的相關檔案,放到android studio的項目中。然後java代碼中,利用jni調用引用的代碼。

... 好,接著往下看吧。

環境準備

  1. 一台Linux 64的機器
  2. 一個帶有AndroidStudioIDE的開發機器

因為環境配置實在複雜,所以我們引入的docker。

docker pull codeskyblue/docker-goandroiddocker run --rm -ti codeskyblue/docker-goandroid bashcd example; echo "view example projects

docker起來之後,什麼就都配置好了,NDK啦,java啦,GO的環境變數了,等等,並且還預裝了vim,gradle,tmux,git,syncthing,svn

開始寫代碼

寫代碼之前,先約定下目錄結構

go的代碼都放在src/golib下,編譯使用make.bash編譯指令碼,看下這個檔案樹

.|-- app.iml|-- build.gradle|-- libs/armeabi-v7a # go編譯產生的so檔案|               `-- libgojni.so|-- main.go_tmpl # 一個模板檔案,先不用管它|-- make.bash # 編譯指令碼,用來產生.so和Java代碼`-- src    |-- golib    |   |-- hi    |   |   |-- go_hi֞֞֞ # 自動產生的程式碼    |   |   |   `-- go_hi.go    |   |   `-- hi.go # 需要編寫的代碼    |   `-- main.go    `-- main        |-- AndroidManifest.xml        |-- java        |   |-- go # 自動產生的程式碼        |   |   |-- Go.java        |   |   |-- Seq.java        |   |   `-- hi        |   |       `-- Hi.java        |   `-- me/shengxiang/gohello # 主要的邏輯代碼        |                      `-- MainActivity.java֞֞֞        `-- res

我已經寫了一個例子,先直接搞下來

git clone https://github.com/codeskyblue/GoHello.git

編譯下,試試行不行(就算不行問題應該也不大,因為大問題都被我消滅了)

cd GoHello/app./make.bash../gradlew build

一切順利的話在build/outputs/apk下應該可以看到app-debug.apk這個檔案。(劇透下,這個檔案只有800多K)

編譯好的我放到qiniu上了,可以點擊下載看看

下面可以嘗試改改,我拋磚引玉說下

開啟hi.go這個檔案

hi.go的內容,比較簡單,我們寫Go代碼主要就是這部分

// Package hi provides a function for saying hello.package hiimport "fmt"func Hello(name string) {    fmt.Printf("Hello, %s!\n", name)    return "(Go)World"}

檔案末尾添加下面這行代碼

func Welcome(name string) string {    return fmt.Sprintf("Welcome %s to the go world", name)}

使用./make.bash重新編譯下

開啟MainActivity.java 修改下OnClickListener事件

    button.setOnClickListener(new View.OnClickListener() {        @Override        public void onClick(View v) {            String message = Hi.Welcome("yourname");            Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();        }    });

編譯運行下,把產生的apk安裝到手機上試試。

原理解讀(有興趣的接著看)

首先說下gobind這個工具。

go_hi/go_hi.go這個檔案時通過gobind這個工具產生的,用來配合一個簡單的程式,產生.so檔案

// go_hi.gopackage go_hiimport (    "golang.org/x/mobile/bind/seq"    "example/hi")func proxy_Hello(out, in *seq.Buffer) {    param_name := in.ReadUTF16()    hi.Hello(param_name)}func init() {    seq.Register("hi", 1, proxy_Hello)}

這個簡單的程式內容是這樣的

// main.gopackage mainimport (    "golang.org/x/mobile/app"    _ "golang.org/x/mobile/bind/java"    _ "example/hi/go_hi")func main() {    app.Run(app.Callbacks{})}

src/MyActivity.java檔案內容是這樣的

import ...import go.Go; // 引入Go這個包import go.hi.Hi; // gobind產生的程式碼public class MainActivity extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        Go.init(getApplicationContext()); // 初始化兩個線程        Hi.Hello("world");    }}

其中有一句Go.init(...)這裡再看go.Go這個包是什麼樣子的

public final class Go {    // init loads libgojni.so and starts the runtime.    public static void init(Context context) {        ... 判斷該函數是否該執行的代碼 -- 省略 --        System.loadLibrary("gojni"); // gojni需要這句        new Thread("GoMain") {            public void run() {                Go.run(); // run()是一個native方法            }        }.start();        Go.waitForRun(); // 這個也是一個native方法        // 這部分可以理解為,啟動了一個後台線程不斷的接收結果到緩衝中。        new Thread("GoReceive") {            public void run() { Seq.receive(); }         }.start();    }    private static boolean running = false;    private static native void run();    private static native void waitForRun();}

MyActivity.java中還有段代碼是 Hi.Hello("world");,開啟Hi.java路徑在src/go/hi/Hi.java,這個檔案也是gobind產生的,是用來給java方便的調用.so檔案

// Hi.java// File is generated by gobind. Do not edit.package go.hi;import go.Seq;public abstract class Hi {    private Hi() {} // uninstantiable    public static void Hello(String name) {        go.Seq _in = new go.Seq();        go.Seq _out = new go.Seq();        _in.writeUTF16(name);        Seq.send(DESCRIPTOR, CALL_Hello, _in, _out); // 下面接著說    }    private static final int CALL_Hello = 1;    private static final String DESCRIPTOR = "hi";}

Seq.send這部分實際上最終調用的是一段go代碼

func Send(descriptor string, code int, req *C.uint8_t, reqlen C.size_t, res **C.uint8_t, reslen *C.size_t) {    fn := seq.Registry[descriptor][code]    in := new(seq.Buffer)    if reqlen > 0 {        in.Data = (*[maxSliceLen]byte)(unsafe.Pointer(req))[:reqlen]    }    out := new(seq.Buffer)    fn(out, in)    seqToBuf(res, reslen, out)}

參考資料

  • 這篇文檔基本算是這個庫的使用入門了。
  • Binding Go and Java 官方的設計文檔
  • docker-goandroid在docker.io上的地址
  • gobind,goapp

後記(吐槽)

這個部落格系統用的是fuxiaohei寫的Goblog

強烈要求更新GoBlog,這文章我剛寫好,然後不小心點了一個回退,結果東西全沒了,我只有重寫了一遍。你能理解我當時什麼心情嗎?

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.