如何将简单的Go脚本作为Android服务运行?

I have the following Go script (testapp.go) that I would like to keep running as a background service:

package main

import(
    "net/http"
    "time"
    "log"
    "golang.org/x/mobile/app"
)

func main() {
    app.Main(func(a app.App) {
        for {
            req, err := http.NewRequest( "GET", "http://0.0.0.0:88/fetch_news", strings.NewReader("topic.title") )
            if err != nil {
                log.Print(err)
            }
            cli := &http.Client{}
            res, err := cli.Do(req)
            if err != nil {
                log.Print(err)
            } else {
                defer res.Body.Close()
                body, _ := ioutil.ReadAll(res.Body)
                returnStr := string(body)
                // Do something with returnStr
            }
            time.Sleep(8 * time.Second)
        }
    })
}

My GoNativeActivity.java looks like this:

package org.golang.app;
import android.app.Activity;
import android.app.NativeActivity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyCharacterMap;

public class GoNativeActivity extends NativeActivity {
    private static GoNativeActivity goNativeActivity;
    public GoNativeActivity() {
        super();
        goNativeActivity = this;
    }
    String getTmpdir() {
        return getCacheDir().getAbsolutePath();
    }
    int getRune(int deviceId, int keyCode, int metaState) {
        try {
            int rune = KeyCharacterMap.load(deviceId).get(keyCode, metaState);
            if (rune == 0) {
                return -1;
            }
            return rune;
        } catch (KeyCharacterMap.UnavailableException e) {
            return -1;
        } catch (Exception e) {
            Log.e("Go", "exception reading KeyCharacterMap", e);
            return -1;
        }
    }
    private void load() {
        // Interestingly, NativeActivity uses a different method
        // to find native code to execute, avoiding
        // System.loadLibrary. The result is Java methods
        // implemented in C with JNIEXPORT (and JNI_OnLoad) are not
        // available unless an explicit call to System.loadLibrary
        // is done. So we do it here, borrowing the name of the
        // library from the same AndroidManifest.xml metadata used
        // by NativeActivity.
        try {
            ActivityInfo ai = getPackageManager().getActivityInfo(
                    getIntent().getComponent(), PackageManager.GET_META_DATA);
            if (ai.metaData == null) {
                Log.e("Go", "loadLibrary: no manifest metadata found");
                return;
            }
            String libName = ai.metaData.getString("android.app.lib_name");
            System.loadLibrary(libName);
        } catch (Exception e) {
            Log.e("Go", "loadLibrary failed", e);
        }
    }
    @Override
    public void onCreate(Bundle savedInstanceState) {
        load();
        super.onCreate(savedInstanceState);
        Intent intent = new Intent(this, org.golang.app.GoNativeService.class);
        startService(intent);
    }
}

My GoNativeService.java looks like this:

package org.golang.app;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

public class GoNativeService extends IntentService {
    @Override
    public void onStart(Intent intent, int startId) {
        Toast.makeText(this,"Service started. onStart()", Toast.LENGTH_SHORT).show();
        handleCommand(intent);
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Toast.makeText(this,"Service started. onStartCommand()", Toast.LENGTH_SHORT).show();
        handleCommand(intent);
        // We want this service to continue running until it is explicitly
        // stopped, so return sticky.
        return START_STICKY;
    }
}

My AndroidManifest.xml file looks like this:

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="org.golang.todo.testapp"
    android:versionCode="1"
    android:versionName="1.0">

    <uses-permission android:name="android.permission.INTERNET" />

    <application android:label="Testapp" android:debuggable="true">
        <activity android:name="org.golang.app.GoNativeActivity"
            android:label="Testactivity"
            android:configChanges="orientation|keyboardHidden">
            <meta-data android:name="android.app.lib_name" android:value="testapp" />
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service 
            android:name="org.golang.app.GoNativeService" 
            android:enabled="true"
            android:exported="true" />
    </application>

</manifest>

This is my work environment:

GOARCH="amd64"
GOBIN="/root/go/bin"
GOCACHE="/root/.cache/go-build"
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/root/go"
GOROOT="/usr/lib/go-1.10"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/go-1.10/pkg/tool/linux_amd64"

This is what my $GOPATH/src/testapp directory looks like:

testapp/
    assets/
        icon.png
    AndroidManifest.xml
    testapp.go

This is what my $GOPATH/src/golang.org/x/mobile/app directory looks like:

app/
    android.c
    app_test.go
    darwin_armx.go
    GoNativeActivity.java
    GoNativeService.java
    internal/
    x11.go
    android.go
    darwin_amd64.go
    darwin_armx.m
    shiny.go
    app.go
    darwin_amd64.m
    doc.go
    x11.c

How can I run my Go script as a background service on Android, so that when the app is exited (MainActivity closes), the background service will continue to fetch news messages?

Note: I am monitoring the requests at my webserver on port 88. I can run the script fine while GoNativeActivity is active, but I would like to know how to build a native app that starts a background service.

Any answers or attempts to point me in the right direction would be appreciated!

1个回答



首先,通常的观察表明,您确实不应该按照自己的要求去做。 正确的方法是使用AlarmManager发送广播,以唤醒单个请求的服务。 这样,系统可以更好地优化功耗。 为此,您的go代码只需处理一个请求,并在进行广播时从Java端调用它。</ p>

但是,要持久地实际运行该服务,您需要启动 https://developer.android.com/guide/components/services所述的“前台服务” 。 反过来,这需要在服务运行时显示通知。 在这种情况下,您可能会发现设备也自行关闭电源,在这种情况下,您将需要考虑获取 https://developer.android.com/reference/android/os/PowerManager.WakeLock 。 除非您非常小心,否则执行此操作会大大减少电池寿命。</ p>

我发现以这种方式启动go代码对于在Android本身上长期运行的Web服务器之类的事情就足够了, 包括使用网络套接字。</ p>
</ div>

展开原文

原文

Firstly, there's the common observation that you really shouldn't be doing what you ask. The correct way is to use AlarmManager to send a broadcast that wakes up the service for a single request. This way the system can better optimize power consumption. For doing this have your go code just process a single request and call it from the Java side whenever a broadcast is made.

However, to actually run the service persistently you will need to be starting a "foreground service" as described https://developer.android.com/guide/components/services. This in turn requires a Notification that is displayed whenever your service is running. In this case you may find the device powering itself off too, in which case you will need to look into acquiring a https://developer.android.com/reference/android/os/PowerManager.WakeLock . Doing this kind of thing can massively reduce battery life unless you are very careful.

I have found launching the go code in this way is sufficient for things like long running web servers on Android itself, including using websockets.

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问