LoginSignup
19
16

More than 5 years have passed since last update.

GolangでAndroidアプリを作る

Last updated at Posted at 2014-10-11

こんにちは @wasabeef_jpです。

GoでAndroidアプリを作るためには
まずcgoの話からはじめて行きたいと思います。

引用:http://wasabeef.jp/goandroid/

環境

  • OS : Mac OS X 10.9.3
  • Go : go1.3 darwin/amd64 (brew install)
  • Android SDK : android-20
  • Android NDK : android-ndk-r10

執筆時点:2014/8/15

cgo

Cgo enables the creation of Go packages that call C code

GoからC/C++にアクセスするために用いるパッケージのこと。
つまり、Cで書かれたライブラリが、Goでも再利用できる。

基本的な使い方

 

まず、Cの関数や型にアクセスするために、cgoのimportを行う

import "C"

import文の上にinclude <ほげほげ.h> と書けば
コンパイル時に自動で読み込まれるので、必要なヘッダを書く

// #include <stdio.h>
// #include <stdlib.h>
import "C"

これで、C.int, *C.char、C.rand とかで、型や関数にアクセスできる

GoからCを呼ぶ

 

Sample1

sample1.go

package main
/*
 #include <stdio.h>

 int total(int a, int b) {
  return a + b;
 }
*/
import "C"
import "fmt"

func main() {
  total := C.total(10, 20)
  fmt.Println(total)
}

Output

# go run sample2.go
30

Sample2

コメントアウトにC言語のソースを書くとEditorとかで認識されないので、C言語は別のファイルにしても問題なく読み込まれます。

  • C言語のメソッドヘッダを作成

sample2.h

#include <stdio.h>

int total(int a, int b) {
    return a + b;
}

sample2.go

package main
// #include "sample2c.h"
import "C"
import "fmt"

func main() {
  total := C.total(10, 20)
  fmt.Println(total)
}

GoからObjective-Cを呼ぶ

 

Sample3

sample3.go

package main
/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Foundation

#import <Foundation/Foundation.h>

void hello() {
    NSLog(@"Hello objective cgo world!");
}
*/
import "C"

func main() {
    C.hello()
}

Output

# go run sample3.go
2014-08-14 18:06:26.903 sample3objc[45354:303] Hello objective cgo world!

参考:

http://unknownplace.org/archives/cgo-and-eventloop.html

golangでAndroidアプリを作る

 

英語:The State of Go Language for Android Native Development

日本語:Androidネイティブ開発に関するGo言語の状況
 

Target Version
  • Android SDK : target=android-20
  • Android NDK : android-ndk-r10

toolchainの作成

Android Toolchain Standalone Compilerとは...
Android向けのライブラリ(.so)を作るときに使うgccとかです

# $ANDROID_NDK/build/tools/make-standalone-toolchain.sh \
# --toolchain=arm-linux-androideabi-4.9 --platform=android-L --install-dir=ndk-toolchain

goandroid

Goandroidとは...

go1.2にpatchをあてて、ARMv7+のAndroidでgoを動かせるようにしたもの
 

まずは、go1.2.2をhg clone

# hg clone -u go1.2.2 https://code.google.com/p/go

goandroidをgit clone

# git clone https://github.com/eliasnaur/goandroid.git
# cp -r patches go/.hg

Mercurialの設定ファイルに追記

go/.hg/hgrc

[extensions]  
mq =
codereview = !

[ui]  
username = me<me@mail.com>

goにpatchをあてる

# cd go/.hg
# hg qpush -a
applying shared-lib-runtime
applying android-tls
applying android-build-hacks
now at: android-build-hacks

golang make

# cd src
# CGO_ENABLED=0 GOOS=linux GOARCH=arm ./make.bash \
# CC="/Users/wasabeef/go/ndk-toolchain/bin/arm-linux-androideabi-gcc" \
# GOOS=linux GOARCH=arm GOARM=7 \
# CGO_ENABLED=1 ../bin/go install -tags android -a -v std  


(省略)

---
Installed Go for linux/arm in /Users/wasabeef/go/go1.2.2
Installed commands in /Users/wasabeef/go/go1.2.2/bin

version表示で動作確認

# ./bin/go version
go version go1.2.2 darwin/amd64

Android NativeAcivity

ANativeActivity_onCreate関数で、golangの関数を登録

main.c

extern void onNativeWindowCreated(ANativeActivity *activity, ANativeWindow* window);
extern void onNativeWindowDestroyed(ANativeActivity *activity, ANativeWindow* window);
extern void onNativeWindowResized(ANativeActivity *activity, ANativeWindow* window);
extern void onInputQueueCreated(ANativeActivity *activity, AInputQueue* queue);
extern void onInputQueueDestroyed(ANativeActivity *activity, AInputQueue* queue);
extern void onCreate(ANativeActivity *activity, void* savedState, size_t savedStateSize);
extern void onDestroy(ANativeActivity *activity);
extern void onResume(ANativeActivity *activity);
extern void onPause(ANativeActivity *activity);
extern void onConfigurationChanged(ANativeActivity *activity);
extern void onWindowFocusChanged(ANativeActivity *activity, int focused);

void ANativeActivity_onCreate(ANativeActivity *activity, void* savedState, size_t savedStateSize) {
    activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
    activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
    activity->callbacks->onInputQueueCreated = onInputQueueCreated;
    activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
    activity->callbacks->onDestroy = onDestroy;
    activity->callbacks->onResume = onResume;
    activity->callbacks->onPause = onPause;
    activity->callbacks->onConfigurationChanged = onConfigurationChanged;
    activity->callbacks->onNativeWindowResized = onNativeWindowResized;
    activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;

    onCreate(activity, savedState, savedStateSize);
}

登録したコールバックを実装していく

main.go

package main

// #include <stdlib.h>
// #include <jni.h>
// #include <android/native_activity.h>
// #include <android/input.h>
// #include <EGL/egl.h>
// #include "main.h"
//
// #cgo LDFLAGS: -landroid -lEGL
import "C"

import (
    "fmt"
    "log"
    "runtime"
    "runtime/debug"
    "unsafe"
)

// (省略)

build.shの調整

主に、pathやarchの設定を環境によって調整

#!/bin/bash

set -e

mkdir -p android/libs/armeabi-v7a
mkdir -p android/obj/local/armeabi-v7a
CC="/Users/wasabeef/go/ndk-toolchain/bin/arm-linux-androideabi-gcc"

if [ -z $GOANDROID ]
then
  GOANDROID="../go"
fi

CC=$CC GOPATH="`pwd`:$GOPATH" GOROOT="" d=linux GOARCH=arm GOARM=7 CGO_ENABLED=1 /Users/a12622/go/go1.2.2/bin/go install $GOFLAGS -v -ldflags="-android -shared -extld $CC -extldflags '-march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16'" -tags android nativeactivity
cp bin/linux_arm/nativeactivity android/libs/armeabi-v7a/libnativeactivity.so
cp bin/linux_arm/nativeactivity android/obj/local/armeabi-v7a/libnativeactivity.so

ant build

# ant -f android/build.xml clean debug install

Buildfile: /Users/wasabeef/go/goandroid/native-activity/android/build.xml

-check-env:
 [checkenv] Android SDK Tools Revision 23.0.2
 [checkenv] Installed at /Applications/android-sdk-macosx

-setup:
     [echo] Project Name: nativeactivity
  [gettype] Project Type: Application

-pre-clean:

clean:
   [delete] Deleting directory /Users/wasabeef/go/goandroid/native-activity/android/bin
   [delete] Deleting directory /Users/wasabeef/go/goandroid/native-activity/android/gen
[getlibpath] Library dependencies:
[getlibpath] No Libraries
   [subant] No sub-builds to iterate on

-set-mode-check:

-set-debug-files:

-check-env:
 [checkenv] Android SDK Tools Revision 23.0.2
 [checkenv] Installed at /Applications/android-sdk-macosx

-setup:
     [echo] Project Name: nativeactivity
  [gettype] Project Type: Application

-set-debug-mode:

-debug-obfuscation-check:

-pre-build:

-build-setup:
[getbuildtools] Using latest Build Tools: 20.0.0
     [echo] Resolving Build Target for nativeactivity...
[gettarget] Project Target:   Android 4.4W
[gettarget] API level:        20
     [echo] ----------
     [echo] Creating output directories if needed...
    [mkdir] Created dir: /Users/wasabeef/go/goandroid/native-activity/android/bin
    [mkdir] Created dir: /Users/wasabeef/go/goandroid/native-activity/android/bin/res
    [mkdir] Created dir: /Users/wasabeef/go/goandroid/native-activity/android/bin/rsObj
    [mkdir] Created dir: /Users/wasabeef/go/goandroid/native-activity/android/bin/rsLibs
    [mkdir] Created dir: /Users/wasabeef/go/goandroid/native-activity/android/gen
    [mkdir] Created dir: /Users/wasabeef/go/goandroid/native-activity/android/bin/classes
    [mkdir] Created dir: /Users/wasabeef/go/goandroid/native-activity/android/bin/dexedLibs
     [echo] ----------
     [echo] Resolving Dependencies for nativeactivity...
[dependency] Ordered libraries:
[dependency]
[dependency] ------------------
     [echo] ----------
     [echo] Building Libraries with 'debug'...
   [subant] No sub-builds to iterate on

-code-gen:
[mergemanifest] Merging AndroidManifest files into one.
[mergemanifest] Manifest merger disabled. Using project manifest only.
     [echo] Handling aidl files...
     [aidl] No AIDL files to compile.
     [echo] ----------
     [echo] Handling RenderScript files...
     [echo] ----------
     [echo] Handling Resources...
     [aapt] Generating resource IDs...
     [echo] ----------
     [echo] Handling BuildConfig class...
[buildconfig] Generating BuildConfig class.

-pre-compile:

-compile:
    [javac] Compiling 2 source files to /Users/wasabeef/go/goandroid/native-activity/android/bin/classes

-post-compile:

-obfuscate:

-dex:
      [dex] input: /Users/wasabeef/go/goandroid/native-activity/android/bin/classes
      [dex] Converting compiled files and external libraries into /Users/wasabeef/go/goandroid/native-activity/android/bin/classes.dex...

-crunch:
   [crunch] Crunching PNG Files in source dir: /Users/wasabeef/go/goandroid/native-activity/android/res
   [crunch] To destination dir: /Users/wasabeef/go/goandroid/native-activity/android/bin/res
   [crunch] Crunched 0 PNG files to update cache

-package-resources:
     [aapt] Creating full resource package...

-package:
[apkbuilder] Current build type is different than previous build: forced apkbuilder run.
[apkbuilder] Creating nativeactivity-debug-unaligned.apk and signing it with a debug key...

-post-package:

-do-debug:
 [zipalign] Running zip align on final apk...
     [echo] Debug Package: /Users/wasabeef/go/goandroid/native-activity/android/bin/nativeactivity-debug.apk
[propertyfile] Creating new property file: /Users/wasabeef/go/goandroid/native-activity/android/bin/build.prop
[propertyfile] Updating property file: /Users/wasabeef/go/goandroid/native-activity/android/bin/build.prop
[propertyfile] Updating property file: /Users/wasabeef/go/goandroid/native-activity/android/bin/build.prop
[propertyfile] Updating property file: /Users/wasabeef/go/goandroid/native-activity/android/bin/build.prop

-post-build:

debug:

install:
     [echo] Installing /Users/wasabeef/go/goandroid/native-activity/android/bin/nativeactivity-debug.apk onto default emulator or device...
     [exec] 6040 KB/s (809846 bytes in 0.130s)
     [exec]   pkg: /data/local/tmp/nativeactivity-debug.apk


     [exec] Success

BUILD SUCCESSFUL
Total time: 1 minute 2 seconds

雑感

ArtVMを積んでるAndroid Lでは上手くうごかなかった。

Genymotionなどのエミュレータではx86で動いてるけど
gccのoptionで-marhc=x86とかにしても"Fatal Signal 11"系で動かなかった。

結論、Go+Androidは正式Supportされるまで、待つ他ないと思います。

(2014/8/15)

19
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
16