AWTK implements cross-process service calls on the Android platform

AWTK implements cross-process service calls on the Android platform

A few days ago, a friend wanted to call the service provided by the printer in the AWTK application to print the collected data. The printer itself has an APP, which provides an external service and comes with an AIDL file.

It is not difficult to say this thing itself, but in the AWTK application, the function of java is called through the function of C language, and then the service of another process is called through the function of java. For embedded programmers who only know C language Speaking of, I don't know java or android, and I have gone around a few big turns. It's really too difficult.

Here, a FooBar service is used to demonstrate the entire development process for reference of children's shoes in need.

1. Develop an APP that provides services

First use Android Studio to create a new normal Android Java project FooBarServer.

1.1 Create a new aidl file.

File location: app/src/main/aidl/org/zlgopen/foobarserver/IFooBarService.aidl

// IFooBarService.aidl
package org.zlgopen.foobarserver;

// Declare any non-default types here with import statements

interface IFooBarService {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    int add(int a, int b);
}

For the convenience of description, here is just an add function, which takes two parameters a and b and returns the sum of the two.

1.2 Create a new service.

File location: app/src/main/java/org/zlgopen/foobarserver/FooBarService.java

package org.zlgopen.foobarserver;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class FooBarService extends Service {
    public FooBarService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return binder;
    }

    private final IFooBarService.Stub binder = new IFooBarService.Stub() {
        public int add(int a, int b) {
            return a + b;
        }
    };
}

1.3 Modify the services provided by the external declaration of AndroidManifest.xml.

        <service
            android:name=".FooBarService"
            android:enabled="true"
            android:process=":remote">
            <intent-filter>
                <action android:name="org.zlgopen.foobarserver.IFooBarService"/>
            </intent-filter>
        </service>

To call across processes, this line of code is critical: android:process=":remote"

2. Develop an APP that uses the service

In order to verify the correctness of the server, we use Android Studio to create a common Android Java application FooBarClient.

2.1 Copy IFooBarService.aidl

Copy app/src/main/aidl/org/zlgopen/foobarserver/IFooBarService.aidl from FooBarService to FooBarClient and keep the directory structure unchanged.

2.2 Modify MainActivity.java

A connection to the service is established and the corresponding function is called.


    public static IFooBarService mFooBarService;
    private ServiceConnection mServiceConn = new ServiceConnection() {
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e("client", "onServiceDisconnected");
            mFooBarService = null;
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e("client", "onServiceConnected");
            mFooBarService = IFooBarService.Stub.asInterface(service);
            try {
                int result = mFooBarService.add(100, 200);
                Log.e("client", Integer.toString(result));
            }catch (RemoteException e) {
                Log.e("client", e.toString());
            }
        }
    };

    public void bindService() {
        Intent intent = new Intent("org.zlgopen.foobarserver.IFooBarService");
        intent.setPackage("org.zlgopen.foobarserver");
        bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE);
    }

    public void unbindService() {
        unbindService(mServiceConn);
    }

Compile and install FooBarServer and FooBarClient.

3. Write AWTK plugin

3.1 C language API interface

AWTK's UI thread and Android's Activity thread are not the same, so all AWTK's plug-ins are asynchronous interfaces. After the call is completed, the execution result is returned through the callback function.

Both parameters and return values ​​use JSON-formatted strings.

/**
 * @method foobar_add
 * 调用 add 函数。
 *
 * > 回调函数是在 AWTK UI 线程中执行的,可以在回调函数中直接操作 AWTK 控件。
 * 
 * @annotation ["static"]
 * @param {int} a a。
 * @param {int} b b。
 * @param {platform_request_on_result_t} on_result 完成时的回调函数。
 * @param {void*} on_result_ctx 完成时的回调函数的上下文。
 *
 * @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
 */
ret_t foobar_add(int a, int b, platform_request_on_result_t on_result, void* on_result_ctx);

The implementation is very simple: package the parameters into a string in JSON format, and then use platform_request_send to send it to the plug-in manager, and the plug-in manager is responsible for forwarding the request to the plug-in.

ret_t foobar_add(int a, int b, platform_request_on_result_t on_result, void* on_result_ctx) {
  ret_t ret = 0;
  char args[64];
  return_value_if_fail(on_result, RET_BAD_PARAMS);
  tk_snprintf(args, sizeof(args)-1, "{\"a\":%d, \"b\":%d}", a, b);
  ret = platform_request_send("foobar", "add", args, on_result, on_result_ctx);

  return ret;
}

3.2 Java language implementation plugin

File location: src/foobar/android/java/org/zlgopen/plugins/foobar/FooBarPlugin.java

The plugin is responsible for establishing the connection with the service, and forwarding the request sent by the AWTK C API to FooBarServer.

The process of establishing a connection is similar to that of FooBarClient, but because Plugin is not an Activity, if you want to call the function of Activity, you need to call it through this.activity.

	public static IFooBarService mFooBarService;
    private ServiceConnection mServiceConn = new ServiceConnection() {
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e("client", "onServiceDisconnected");
            mFooBarService = null;
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e("client", "onServiceConnected");
            mFooBarService = IFooBarService.Stub.asInterface(service);
        }
    };

    public void bindService() {
        Intent intent = new Intent("org.zlgopen.foobarserver.IFooBarService");
        intent.setPackage("org.zlgopen.foobarserver");

        this.activity.bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE);
    }

    public void unbindService() {
        this.activity.unbindService(mServiceConn);
    }

The run function handles requests from the AWTK C API and forwards them to FooBarServer:

  public boolean run(String action, String callerInfo, String args) {
    try {
      this.callerInfo = callerInfo;
      JSONObject json = new JSONObject(args);

      if (action.equals("add")) {
        int a = json.getInt("a");
        int b = json.getInt("b");
        this.Add(a, b);
      } else {
        Log.v("AWTK", "not supported action");
      }
    } catch (JSONException e) {
      Log.v("AWTK", e.toString());
      PluginManager.writeResult(this.callerInfo, "fail");
    }

    return true;
  }

  void Add(int a, int b) {
		int sum = 0;

		try {
				sum = mFooBarService.add(a, b);
				Log.w("client", Integer.toString(sum));
		}catch (RemoteException e) {
				Log.e("client", e.toString());
		}

    String result = "{\"action\":\"add\"" + ",\"result\":" + Integer.toString(sum) + "}";
    PluginManager.writeResult(this.callerInfo, result);

    return;
  }

3.3 AWTK C language calling example

  • include header files
#include "foobar/foobar.h
  • call a function and display the result
static ret_t foobar_on_result(void* ctx, const char* data){
  widget_t* result_label = WIDGET(ctx);
  conf_doc_t* doc = conf_doc_load_json(data, strlen(data));
  int result = conf_doc_get_int(doc, "result", 0);
  log_debug("foobar:%s\n result:%d\n", data, result);
  conf_doc_destroy(doc);

  widget_set_text_utf8(result_label, data);
  widget_invalidate_force(result_label, NULL);

  return RET_OK;
}

static ret_t on_click(void* ctx, event_t* e) {
  foobar_add(100, 200, foobar_on_result, ctx);
  return RET_OK;
}

For the complete code, please refer to awtk-mobile-plugins

{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324071575&siteId=291194637