2015: add gophercon go-on-mobile talk slide and demo Change-Id: I8be9d01dabf8800bf6b37d5144fac3d743b08af9 Reviewed-on: https://go-review.googlesource.com/12040 Reviewed-by: David Crawshaw <crawshaw@golang.org>
diff --git a/2015/gophercon-go-on-mobile.slide b/2015/gophercon-go-on-mobile.slide new file mode 100644 index 0000000..58a48ac --- /dev/null +++ b/2015/gophercon-go-on-mobile.slide
@@ -0,0 +1,340 @@ +Go on Mobile + +GopherCon 2015 + +Hana Kim +Google + +* Caution + +.image gophercon-go-on-mobile/caution.png 300 _ + +The Go Mobile project is experimental. Use this at your own risk. + +While we are working hard to improve it, neither Google nor the Go +team can provide end-user support. + +* Background + +Mobile support was frequently requested + +Some users built their own Go binaries for Android with cgo + external linking through NDK tool chains + +Some Android Apps used Go even before Go 1.4 + +- Camlistore android app (out-of-process model) +- Goandroid+Mandala (in-process model) +- ... + +* golang.org/x/mobile + +Goal: Bring Go to Mobile Platforms + +Why? + +- Use Go to program a complete system (server/client) +- Write a single cross-platform Go library +- Bring a simple language and development tooling to mobile + +* Two ways of using Go + +Native Apps + +- Write the whole app in Go +- Use Go packages for graphics, event handling, audio, etc. + +SDK Apps + +- Write Android UI in Java, iOS UI in Objective-C/Swift +- Write common functionality in Go as a library + +* Native Apps + +* Challenge #1: Cross-platform APIs + +Work for Android, iOS, and Desktop environments + +Provide a rich set of APIs + +Follow idiomatic Go style + +* Demo: Hello, Gopher! + +.image gophercon-go-on-mobile/gophercloud.png 400 _ + +This program uses the packages from golang.org/x/mobile repo +There is no Java or Objective-C or C in my code + +* What's available? + +golang.org/x/mobile/... + +- [[http://golang.org/x/mobile/app][app: App control]] +- [[http://golang.org/x/mobile/asset][asset: Asset management]] +- [[http://golang.org/x/mobile/gl][gl: OpenGL ES 2]] +- [[https://golang.org/x/mobile/event][event: Events]] +- [[https://golang.org/x/mobile/geom][geom: Screen geometry]] + +golang.org/x/mobile/exp/... + +- [[https://golang.org/x/mobile/exp/audio][audio: Audio]] +- [[https://golang.org/x/mobile/exp/font][font: System font]] +- [[https://golang.org/x/mobile/exp/sprite][sprite: 2-D rendering]] +- [[https://golang.org/x/mobile/exp/sensor][sensor: Sensors]] + +* Challenge #2: Build systems + +Dealing with + +- Toolchain installation + +- Cross compilation for `GOOS/GOARCH` combos + +- Android/iOS-specific build details + +That is not fun! + +* The gomobile tool + + $ go get golang.org/x/mobile/cmd/gomobile + +Simplifies toolchain installation and app deployment + +To install the Android/iOS compiler tool chain: + + $ gomobile init + +To build an Android APK and an iOS app + + $ gomobile -target=android build + $ gomobile -target=ios build + +(Demo) + +* SDK Apps + +* Go as a library + +Go 1.5 can build Go programs as a library that can be used by non-Go programs + +- Shared library for dynamic linking (`-buildmode=c-shared`) +- Archive file for static linking (`-buildmode=c-archive`) + +Functions marked with `//export` cgo annotations are callable. + +.link http://golang.org/s/execmodes + +* Working with Foreign Languages + +.image gophercon-go-on-mobile/gobind.png 300 _ + +Manually mapping data structures and functions between languages is tedious and error-prone! + + +* The gobind tool + + $ go get golang.org/x/mobile/cmd/gobind + +Automates language binding through code generation + +Defines the language binding from exported Go APIs; no explicit annotation + +Currently supports a [[http://golang.org/x/mobile/cmd/gobind][subset of Go types]] + + +* Binding Functions, Basic Types & Errors + +Go API + + package mypkg + + func Hello() (string, error) { return "Gopher", nil } + +Generated Java API + + public abstract class Mypkg { + public static String Hello() throws Exception { ... } + } + +Generated Objective-C API + + FOUNDATION_EXPORT BOOL GoMypkgHello(NSString** ret0_, NSError** error); + +* Binding Structs + + package mypkg + + type Counter struct { + Value int64 + } + + func (c *Counter) Inc() { + c.Value++ + } + + func NewCounter() *Counter { + return &Counter{} + } + +* Generated Java API + + public abstract class Mypkg { + public static final class Counter { + public void Inc() { ... } + public long GetValue() { ... } + public void SetValue(long value) { ... } + } + + public static Counter NewCounter() { ... } + } + +Use it from Java + + Counter counter = NewCounter(); + counter.SetValue(12345); + counter.Inc(); + + +* Generated Objective-C API + + @interface GoMypkgCounter : NSObject { } + @property(strong, readonly) GoSeqRef *ref; + - (int64_t)Value; + - (void)setValue:(int64_t)v; + - (void)Inc; + @end + + FOUNDATION_EXPORT GoMypkgCounter* GoMypkgNewCounter(); + +Use it from Objective-C + + GoMypkgCounter* counter = GoMypkgNewCounter(); + [counter setValue:12345]; + [counter Inc]; + +* How to build it? + +.image gophercon-go-on-mobile/memegobind.jpg 500 _ + + +* The gomobile bind command + +Simplifies the build process. For example, for Android, + +- Generates language bindings for Go packages + +- Compiles Go code to a shared library + +- Compiles the generated target language code + +- Bundles everything into a `.aar` file (modern way to distribute android libraries) + +(DEMO) + +iOS support is a work in progress. + +* Android Studio Integration + +Android Studio 1.2+ supports `.aar` import. + +.image gophercon-go-on-mobile/androidstudio2.png 250 _ + +To update the .aar, + +- Build script to invoke `gomobile` `bind`, or +- Gradle plugin to invoke `gomobile` `bind` and publish the output + + +* The Story of Ivy + +The [[robpike.io/ivy][Ivy]] is a command line tool developed by Rob Pike + +It's a useful desktop calculator that handles big int, rational and floating-point numbers, vectors, matrices, ... + +.image gophercon-go-on-mobile/ivyscreenshot2.png 300 _ + +It is in fact an interpreter for an [[https://en.wikipedia.org/wiki/APL_(programming_language)][APL]]-like language + +* Ivy on Mobile? + +~5k lines of Go code (not including tests, docs) + +Dependency on `math`, `math/big`, `math/rand`, `unicode`, ... + +.image gophercon-go-on-mobile/canihas.jpg 300 _ + +Rewriting in Java or Objective-C is a non-starter + +* Ivy apps + +.image gophercon-go-on-mobile/ivymobile.png 300 _ +.caption Ivy logo by [[http://www.reneefrench.com][Renée French]] +.link https://play.google.com/store/apps/details?id=org.golang.ivy Google Play Store +.link https://itunes.apple.com/us/app/ivy-big-number-calculator/id1012116478 Apple App Store + +* Gomobile bind + +Write it once as a library in Go + +Enjoy great language features and packages available in Go + +* Where are we now? + +* Go 1.4: Hello Android! + +Released in December 2014 + +Can build Android apps (`arm`) + +Android builder + +The `gobind` tool for Java and Go language binding + +Packages for cross-device apps: basic app control, OpenGL ES 2, touch + +.link https://golang.org/s/go14android +.link https://golang.org/s/gobind + +* Go 1.5: Hello iOS! + +Planned release early August 2015 + +Experimental support for iOS (`arm,arm64`) + +iOS builder + +* Go 1.5: Go programs as libraries + +Can call Go functions from foreign language in a clean way + +.link golang.org/s/execmodes + +* Go 1.5: Better tools & more packages + +`golang.org/x/mobile` repo getting better + +- The `gomobile` tool for mobile app/library build + +- Extended `gobind` tool: Objective-C binding + +- `golang.org/x/mobile/exp`: experimenting with audio, sensor, sprite, ... + +* Go 1.6+ + +- Improvement in GL/UI packages + +- More APIs available to "pure Go" apps + +- Testing, profiling, debugging + +- Support for more platforms (e.g. android/x86, iOS simulator) + +- Richer type support in `gobind` + +- IDE integration + +* Contributions from Go community + +.image gophercon-go-on-mobile/contributors.png 480 _ +.caption git log | word_cloud +
diff --git a/2015/gophercon-go-on-mobile/README b/2015/gophercon-go-on-mobile/README new file mode 100644 index 0000000..1732cd8 --- /dev/null +++ b/2015/gophercon-go-on-mobile/README
@@ -0,0 +1,38 @@ +Demo Setup +---------------------- + +- Download and install Android SDK + +https://developer.android.com/sdk/index.html +Or, easiest way is to install Android Studio. + + +- Download go1.5 and build for your host. + +- Set the following environment variables. + +GOPATH: your go path +ANDROID_HOME: Android SDK directory +PATH: make sure $GOROOT/bin, $GOPATH/bin are included in the path + +- Install the gomobile tool and run init before demo. + +% go install golang.org/x/mobile/cmd/gomobile +% gomobile init + +- Hello Gopher demo + +% demo1.bash + +For android screen mirroring, I used Mobizen (mobizen.com). +For ios screen mirroring, you can use quicktime. + +- Gobind demo + +% demo2.bash + +- Ivy demo: In my gophercon talk, I used pre-recorded video +clips for mobile versions and ran the command line version from +my laptop in order to emphasize the cross-platform support. + +Enjoy.
diff --git a/2015/gophercon-go-on-mobile/androidstudio2.png b/2015/gophercon-go-on-mobile/androidstudio2.png new file mode 100644 index 0000000..add1106 --- /dev/null +++ b/2015/gophercon-go-on-mobile/androidstudio2.png Binary files differ
diff --git a/2015/gophercon-go-on-mobile/canihas.jpg b/2015/gophercon-go-on-mobile/canihas.jpg new file mode 100644 index 0000000..1d94c61 --- /dev/null +++ b/2015/gophercon-go-on-mobile/canihas.jpg Binary files differ
diff --git a/2015/gophercon-go-on-mobile/caution.png b/2015/gophercon-go-on-mobile/caution.png new file mode 100644 index 0000000..cdb9faa --- /dev/null +++ b/2015/gophercon-go-on-mobile/caution.png Binary files differ
diff --git a/2015/gophercon-go-on-mobile/contributors.png b/2015/gophercon-go-on-mobile/contributors.png new file mode 100644 index 0000000..0da8a6c --- /dev/null +++ b/2015/gophercon-go-on-mobile/contributors.png Binary files differ
diff --git a/2015/gophercon-go-on-mobile/demo1.bash b/2015/gophercon-go-on-mobile/demo1.bash new file mode 100755 index 0000000..8d750ed --- /dev/null +++ b/2015/gophercon-go-on-mobile/demo1.bash
@@ -0,0 +1,20 @@ +#!/bin/bash + +prompt() { + read -p "$1" +} + +cd hello + +declare -a arr=( +"wc -l main.go" +"go run main.go" +"gomobile install -target=android" +) + +for i in "${arr[@]}" +do + prompt "\$ $i" + $i + echo +done
diff --git a/2015/gophercon-go-on-mobile/demo2.bash b/2015/gophercon-go-on-mobile/demo2.bash new file mode 100755 index 0000000..d377162 --- /dev/null +++ b/2015/gophercon-go-on-mobile/demo2.bash
@@ -0,0 +1,24 @@ +#!/bin/bash + +prompt() { + read -p "$1" +} + +declare -a arr=( +"cd mypkg" +"tree" +"cat mypkg.go" +"export ANDROID_HOME=${ANDROID_HOME}" +"gomobile bind ." +"tree" +"unzip -l mypkg.aar" +) + +for i in "${arr[@]}" +do + prompt "\$ $i" + $i + echo +done + +rm mypkg.aar
diff --git a/2015/gophercon-go-on-mobile/gobind.png b/2015/gophercon-go-on-mobile/gobind.png new file mode 100644 index 0000000..905b5ea --- /dev/null +++ b/2015/gophercon-go-on-mobile/gobind.png Binary files differ
diff --git a/2015/gophercon-go-on-mobile/gophercloud.png b/2015/gophercon-go-on-mobile/gophercloud.png new file mode 100644 index 0000000..2bb5d25 --- /dev/null +++ b/2015/gophercon-go-on-mobile/gophercloud.png Binary files differ
diff --git a/2015/gophercon-go-on-mobile/hello/assets/gophersmall.png b/2015/gophercon-go-on-mobile/hello/assets/gophersmall.png new file mode 100644 index 0000000..53b4b4a --- /dev/null +++ b/2015/gophercon-go-on-mobile/hello/assets/gophersmall.png Binary files differ
diff --git a/2015/gophercon-go-on-mobile/hello/assets/hello.wav b/2015/gophercon-go-on-mobile/hello/assets/hello.wav new file mode 100644 index 0000000..1551ebf --- /dev/null +++ b/2015/gophercon-go-on-mobile/hello/assets/hello.wav Binary files differ
diff --git a/2015/gophercon-go-on-mobile/hello/main.go b/2015/gophercon-go-on-mobile/hello/main.go new file mode 100644 index 0000000..32aba94 --- /dev/null +++ b/2015/gophercon-go-on-mobile/hello/main.go
@@ -0,0 +1,207 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Based on golang.org/x/mobile/example/audio + +package main + +import ( + "image" + "log" + "time" + + _ "image/png" + + "golang.org/x/mobile/app" + "golang.org/x/mobile/asset" + "golang.org/x/mobile/event/config" + "golang.org/x/mobile/event/lifecycle" + "golang.org/x/mobile/event/paint" + "golang.org/x/mobile/event/touch" + "golang.org/x/mobile/exp/app/debug" + "golang.org/x/mobile/exp/audio" + "golang.org/x/mobile/exp/f32" + "golang.org/x/mobile/exp/sprite" + "golang.org/x/mobile/exp/sprite/clock" + "golang.org/x/mobile/exp/sprite/glsprite" + "golang.org/x/mobile/geom" + "golang.org/x/mobile/gl" +) + +func main() { + app.Main(func(a app.App) { + for e := range a.Events() { + switch e := app.Filter(e).(type) { + case lifecycle.Event: + switch e.Crosses(lifecycle.StageVisible) { + case lifecycle.CrossOn: + onStart() + case lifecycle.CrossOff: + onStop() + } + case config.Event: + globalCfg = e // dimension change. move to the center. + touchLoc = geom.Point{globalCfg.Width / 2, globalCfg.Height / 2} + case paint.Event: + onPaint(globalCfg) + a.EndPaint() + case touch.Event: + onTouch(e) + } + } + }) +} + +const ( + width = 72 + height = 74 +) + +var ( + startClock = time.Now() + eng = glsprite.Engine() + scene *sprite.Node + + player *audio.Player + + started = false + activate = false + acceptTouch = false + touchLoc geom.Point + globalCfg config.Event +) + +func onTouch(t touch.Event) { + if t.Type != touch.TypeStart { + return + } + + touchLoc = t.Loc + acceptTouch = true + if !activate { + activate = true + } +} + +func onStart() { + gl.Enable(gl.BLEND) + gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) + + rc, err := asset.Open("hello.wav") + if err != nil { + log.Fatal(err) + } + player, err = audio.NewPlayer(rc, 0, 0) + if err != nil { + log.Fatal(err) + } +} + +func onStop() { + player.Close() +} + +func onPaint(c config.Event) { + if !started { + touchLoc = geom.Point{c.Width / 2, c.Height / 2} + started = true + } + if scene == nil { + loadScene() + } + gl.ClearColor(242/255.0, 240/255.0, 217/255.0, 1) // gophercon bg color + gl.Clear(gl.COLOR_BUFFER_BIT) + + now := clock.Time(time.Since(startClock) * 60 / time.Second) + eng.Render(scene, now, c) + debug.DrawFPS(c) +} + +func newNode() *sprite.Node { + n := &sprite.Node{} + eng.Register(n) + scene.AppendChild(n) + return n +} + +func loadScene() { + gopher := loadGopher() + scene = &sprite.Node{} + eng.Register(scene) + eng.SetTransform(scene, f32.Affine{ + {1, 0, 0}, + {0, 1, 0}, + }) + + var x, y float32 + dx, dy := float32(1), float32(1) + + n := newNode() + n.Arranger = arrangerFunc(func(eng sprite.Engine, n *sprite.Node, t clock.Time) { + eng.SetSubTex(n, gopher) + + if acceptTouch { + dx = (float32(touchLoc.X) - x) / 60 + dy = (float32(touchLoc.Y) - y) / 60 + acceptTouch = false + hello() + x += dx + y += dy + } else if activate { + if x < 0 { + dx = 1 + } + if y < 0 { + dy = 1 + } + if x+width > float32(globalCfg.Width) { + dx = -1 + } + if y+height > float32(globalCfg.Height) { + dy = -1 + } + x += dx + y += dy + } + + if dx < 0 { + eng.SetTransform(n, f32.Affine{ // change direction + {-width, 0, x + width}, + {0, height, y}, + }) + } else { + eng.SetTransform(n, f32.Affine{ + {width, 0, x}, + {0, height, y}, + }) + } + }) +} + +func hello() { + player.Seek(0) + player.Play() +} + +func loadGopher() sprite.SubTex { + a, err := asset.Open("gophersmall.png") + if err != nil { + log.Fatal(err) + } + defer a.Close() + + img, _, err := image.Decode(a) + if err != nil { + log.Fatal(err) + } + t, err := eng.LoadTexture(img) + if err != nil { + log.Fatal(err) + } + return sprite.SubTex{t, image.Rect(0, 0, 360, 370)} +} + +type arrangerFunc func(e sprite.Engine, n *sprite.Node, t clock.Time) + +func (a arrangerFunc) Arrange(e sprite.Engine, n *sprite.Node, t clock.Time) { a(e, n, t) }
diff --git a/2015/gophercon-go-on-mobile/ivyabout.png b/2015/gophercon-go-on-mobile/ivyabout.png new file mode 100644 index 0000000..3b515f7 --- /dev/null +++ b/2015/gophercon-go-on-mobile/ivyabout.png Binary files differ
diff --git a/2015/gophercon-go-on-mobile/ivymobile.png b/2015/gophercon-go-on-mobile/ivymobile.png new file mode 100644 index 0000000..3ea7d21 --- /dev/null +++ b/2015/gophercon-go-on-mobile/ivymobile.png Binary files differ
diff --git a/2015/gophercon-go-on-mobile/ivyscreenshot2.png b/2015/gophercon-go-on-mobile/ivyscreenshot2.png new file mode 100644 index 0000000..c0701b7 --- /dev/null +++ b/2015/gophercon-go-on-mobile/ivyscreenshot2.png Binary files differ
diff --git a/2015/gophercon-go-on-mobile/memegobind.jpg b/2015/gophercon-go-on-mobile/memegobind.jpg new file mode 100644 index 0000000..16b5a75 --- /dev/null +++ b/2015/gophercon-go-on-mobile/memegobind.jpg Binary files differ
diff --git a/2015/gophercon-go-on-mobile/mypkg/assets/myassets.txt b/2015/gophercon-go-on-mobile/mypkg/assets/myassets.txt new file mode 100644 index 0000000..7e2f179 --- /dev/null +++ b/2015/gophercon-go-on-mobile/mypkg/assets/myassets.txt
@@ -0,0 +1 @@ +assets
diff --git a/2015/gophercon-go-on-mobile/mypkg/mypkg.go b/2015/gophercon-go-on-mobile/mypkg/mypkg.go new file mode 100644 index 0000000..12c88ec --- /dev/null +++ b/2015/gophercon-go-on-mobile/mypkg/mypkg.go
@@ -0,0 +1,7 @@ +package mypkg + +import "fmt" + +func Hello(name string) string { + return fmt.Sprintf("Hello, %s!", name) +}