当前位置:首页 > 技术分析 > 正文内容

用Go语言写Android应用—— (1) 用Go写本地应用

ruisui883个月前 (02-18)技术分析19

·从看小例子开始 ·

step1下载安装gomobile工具

首先安装1.5以上版本的Go语言环境,这个大家都应该有了。

然后需要通过科学上网方法去下载gomobile命令:

go get golang.org/x/mobile/cmd/gomobile

接着需要通过gomobile init去下载Android NDK的部分toolchain,执行下面的命令:

gomobile init

可以去android网站上下载一份最新的NDK以备用,将来遇上缺什么文件的话,就从NDK里面复制就是了。

下载地址在
:https://developer.android.com/ndk/downloads/index.html

一切就绪了之后,先运行个例子试一试吧:

gomobile build -target=android golang.org/x/mobile/example/basic

成功之后,就生成了basic.apk。

可以通过gomobile install命令安装这个apk:

gomobile install golang.org/x/mobile/example/basic

当然啦,apk都生成了,直接用adb install就是了。

basic例子的功能很简单,红底上画一个绿色渐变的三角形,随着手指的点击事件,三角形的直角顶点的位置跟着一起走。

step2basic例子分析

纯用Go写的Android代码,与Android NDK用C++写的代码异曲同工,都是用OpenGL/ES的命令直接作画的方式。

我们来看下这个不长的例子,涉及到Go语言相关或者是OpenGL相关的不理解的不要紧,后面我们都会介绍,我们先过几个例子找找感觉:

2.1引用包

第一步是引用了一堆要用的包,跟app相关,event相关,openGL相关。

package mainimport ( "encoding/binary"

"log"

"golang.org/x/mobile/app"

"golang.org/x/mobile/event/lifecycle"

"golang.org/x/mobile/event/paint"

"golang.org/x/mobile/event/size"

"golang.org/x/mobile/event/touch"

"golang.org/x/mobile/exp/app/debug"

"golang.org/x/mobile/exp/f32"

"golang.org/x/mobile/exp/gl/glutil"

"golang.org/x/mobile/gl")

2.2定义变量

基本是OpenGL相关的几个值,还有颜色,X和Y的位置。

var (

images *glutil.Images

fps *debug.FPS

program gl.Program

position gl.Attrib

offset gl.Uniform

color gl.Uniform

buf gl.Buffer

green float32

touchX float32

touchY float32

)

2.3主函数

先向app.Main中注册我们的主函数。

func main() {

app.Main(func(a app.App) { var glctx gl.Context

var sz size.Event

下面就是一个典型的消息驱动的循环,app将事件传给我们的主函数,我们根据事件来处理。GUI系统的代码的框架都差不多哈。

for e := range a.Events() { switch e := a.Filter(e).(type) { case lifecycle.Event: switch e.Crosses(lifecycle.StageVisible) { case lifecycle.CrossOn:

glctx, _ = e.DrawContext.(gl.Context)

onStart(glctx)

a.Send(paint.Event{}) case lifecycle.CrossOff:

onStop(glctx)

glctx = nil

} case size.Event:

sz = e

touchX = float32(sz.WidthPx / 2)

touchY = float32(sz.HeightPx / 2) case paint.Event: if glctx == nil || e.External { // As we are actively painting as fast as

// we can (usually 60 FPS), skip any paint

// events sent by the system.

continue

}

onPaint(glctx, sz)

a.Publish() // Drive the animation by preparing to paint the next frame

// after this one is shown.

a.Send(paint.Event{}) case touch.Event:

touchX = e.X

touchY = e.Y

}

}

})

}

后面基本上就需要一些OpenGL的知识了:

func onStart(glctx gl.Context) { var err error

通过glutil.CreateProgram创建一个程序,OpenGL里程序是将顶点着色器和片段着色器绑定在一起的实体。

program, err = glutil.CreateProgram(glctx, vertexShader, fragmentShader) if err != nil { log.Printf("error creating GL program: %v", err) return

}

buf = glctx.CreateBuffer()

glctx.BindBuffer(gl.ARRAY_BUFFER, buf)

glctx.BufferData(gl.ARRAY_BUFFER, triangleData, gl.STATIC_DRAW)

position = glctx.GetAttribLocation(program, "position")

color = glctx.GetUniformLocation(program, "color")

offset = glctx.GetUniformLocation(program, "offset")

images = glutil.NewImages(glctx)

fps = debug.NewFPS(images)

}

func onStop(glctx gl.Context) {

glctx.DeleteProgram(program)

glctx.DeleteBuffer(buf)

fps.Release()

images.Release()

}

onPaint的过程,是个标准的OpenGL绘制三角形的流程:

func onPaint(glctx gl.Context, sz size.Event) {

glctx.ClearColor(1, 0, 0, 1)

glctx.Clear(gl.COLOR_BUFFER_BIT)

glctx.UseProgram(program)

green += 0.01

if green > 1 {

green = 0

}

glctx.Uniform4f(color, 0, green, 0, 1)

glctx.Uniform2f(offset, touchX/float32(sz.WidthPx), touchY/float32(sz.HeightPx))

glctx.BindBuffer(gl.ARRAY_BUFFER, buf)

glctx.EnableVertexAttribArray(position)

glctx.VertexAttribPointer(position, coordsPerVertex, gl.FLOAT, false, 0, 0)

glctx.DrawArrays(gl.TRIANGLES, 0, vertexCount)

glctx.DisableVertexAttribArray(position)

fps.Draw(sz)

}

下面是三角形的三个顶点的坐标:

var triangleData = f32.Bytes(binary.LittleEndian, 0.0, 0.4, 0.0, // top left

0.0, 0.0, 0.0, // bottom left

0.4, 0.0, 0.0, // bottom right)const (

coordsPerVertex = 3

vertexCount = 3)

最后是我们创建顶点着色器时所使用的GLSL:

const vertexShader = `#version 100
uniform vec2 offset;

attribute vec4 position;void main() { // offset comes in with x/y values between 0 and 1.

// position bounds are -1 to 1.

vec4 offset4 = vec4(2.0*offset.x-1.0, 1.0-2.0*offset.y, 0, 0);

gl_Position = position + offset4;

}`

const fragmentShader = `#version 100
precision mediump float;uniform vec4 color;void main() { gl_FragColor = color;

}`

step3对照C++所写的native activity

我们来对照下,Android用NDK来写这种native的activity都需要做什么吧。总的代码比Go版本的还是长不少,我们就挑个Android的主函数看一下:

void android_main(struct android_app* state) { struct engine engine; // Make sure glue isn't stripped.

app_dummy(); memset(&engine, 0, sizeof(engine));

state->userData = &engine;

state->onAppCmd = engine_handle_cmd;

state->onInputEvent = engine_handle_input;

engine.app = state;

... if (state->savedState != NULL) { // We are starting with a previous saved state; restore from it.

engine.state = *(struct saved_state*)state->savedState;

} // loop waiting for stuff to do.

while (1) { // Read all pending events.

int ident; int events; struct android_poll_source* source; // If not animating, we will block forever waiting for events.

// If animating, we loop until all events are read, then continue

// to draw the next frame of animation.

while ((ident=ALooper_pollAll(engine.animating ? 0 : -1, NULL, &events,

(void**)&source)) >= 0) { // Process this event.

if (source != NULL) {

source->process(state, source);

}

... // Check if we are exiting.

if (state->destroyRequested != 0) {

engine_term_display(&engine); return;

}

} if (engine.animating) { // Done with events; draw next animation frame.

engine.state.angle += .01f; if (engine.state.angle > 1) {

engine.state.angle = 0;

} // Drawing is throttled to the screen update rate, so there

// is no need to do timing here.

engine_draw_frame(&engine);

}

}

}//END_INCLUDE(all)

Android例子中用的OpenGL比上面Go的例子要简单一些:

static void engine_draw_frame(struct engine* engine) { if (engine->display == NULL) { // No display.

return;

} // Just fill the screen with a color.

glClearColor(((float)engine->state.x)/engine->width, engine->state.angle,

((float)engine->state.y)/engine->height, 1);

glClear(GL_COLOR_BUFFER_BIT);

eglSwapBuffers(engine->display, engine->surface);

}

小结

上面的例子,除去了OpenGL的知识以外,我们不需要知道任何跟Android系统相关的知识。

别小看了这段小小的代码,在gomobile的支持下,它可是跨平台的哟。

下一期,我们讨论更加激动人心的话题,如何从Android的Java代码调用Go的代码。

更多深度技术内容,请关注云栖社区微信公众号:yunqiinsight。

扫描二维码推送至手机访问。

版权声明:本文由ruisui88发布,如需转载请注明出处。

本文链接:http://www.ruisui88.com/post/2065.html

标签: go数组
分享给朋友:

“用Go语言写Android应用—— (1) 用Go写本地应用” 的相关文章

Lindroid开源应用:在安卓手机 / 平板上安装 Linux发行版

IT之家 6 月 19 日消息,Erfan Abdi 本月发布了 Lindroid 开源应用程序,让用户可以在安卓手机上安装 GNU / Linux 发行版,在完全支持手机硬件的情况下可以运行 Linux 应用程序。Lindroid 开源应用程序就是将 Linux 放入容器中,使用 Halium 等...

Java教程:gitlab-使用入门

1 导读本教程主要讲解了GitLab在项目的环境搭建和基本的使用,可以帮助大家在企业中能够自主搭建GitLab服务,并且可以GitLab中的组、权限、项目自主操作GitLab简介GitLab环境搭建GitLab基本使用(组、权限、用户、项目)2 GitLab简介GitLab是整个DevOps生命周期...

使用cgroup限制进程资源

这里使用containerd项目中的cgroup包来实现进程资源限制。先写一个耗费一个CPU并且一秒增加10m内存的测试进程package mainimport ( "fmt" "math/rand" "time")func main() { go f...

面试被逼疯:聊聊Python Import System?

面试官一个小时逼疯面试者:聊聊Python Import System?对于每一位Python开发者来说,import这个关键字是再熟悉不过了,无论是我们引用官方库还是三方库,都可以通过import xxx的形式来导入。可能很多人认为这只是Python的一个最基础的常识之一,似乎没有可以扩展的点了,...

三维家-系统快捷键使用

快键件使用:通过简单的键盘+鼠标操作,快速完成搭配。1.基础快捷键1) Ctrl+V:复制选中对象第一步:鼠标左击物体,按下Ctrl+V 即可复制选中对象。2) Ctrl+G:组合多选对象第一步:按住Ctrl键多选对象--按住Ctrl+G--确定。3) Ctrl+B:解组选中对象第一步:左击选中对象...

基于Spring Cloud+VUE的多租户小程序商城源码「快速二开可商用」

一、系统介绍JooLun平台是一个专注微信快速二开系统研发的平台,采用Java语言开发,使用的是最新微服务前后端分离技术,目前有公众号和小程序商城两个版本,有公众号后台管理、小程序商城。基于Spring Cloud微服务+VUE实现的核心框架多租户小程序商城源码,核心框架采用SpringBoot2+...