問題背景
- 客戶需要rom提供一些系統(tǒng)app才能操作的接口;
- 為客戶開發(fā)了一些在rom中實現(xiàn)的功能,客戶需要自己調(diào)用功能接口;
設(shè)計思路
- 通過增加一個系統(tǒng)的模塊(視具體需求擁有系統(tǒng)簽名或者system uid),提供aidl文件給第三方app進行跨進程調(diào)用。
- 在提供aidl文件的基礎(chǔ)上,通過封裝sdk,提供aar或者jar包給第三方app。
操作步驟
server端編碼
android studio 創(chuàng)建OpenApiDemo工程
(這個工程是要放在rom中編譯的,作為三方app aidl調(diào)用的對象)
以傳輸apn信息為例(如果不需要通過跨進程傳輸對象,直接參考步驟3)
-
首先需要創(chuàng)建一個KimApn.aidl
ps:注意包名位置
image.png
// KimApn.aidl
package com.kim.openapi;
// Declare any non-default types here with import statements
parcelable KimApn;
- 定義一個KimApn類
package com.kim.openapi;
import android.os.Parcel;
import android.os.Parcelable;
public class KimApn implements Parcelable {
private String name;
private String apn;
private String httpProxy;
private String httpPort;
private String user;
private String server;
private String password;
public static class Builder {
private String name;
private String apn;
private String httpProxy;
private String httpPort;
private String user;
private String server;
private String password;
public Builder setName(String name) {
this.name = name;
return this;
}
public Builder setApn(String apn) {
this.apn = apn;
return this;
}
public Builder setHttpProxy(String httpProxy) {
this.httpProxy = httpProxy;
return this;
}
public Builder setHttpPort(String httpPort) {
this.httpPort = httpPort;
return this;
}
public Builder setUser(String user) {
this.user = user;
return this;
}
public Builder setServer(String server) {
this.server = server;
return this;
}
public Builder setPassword(String password) {
this.password = password;
return this;
}
public KimApn createKimAPN() {
return new KimApn(name, apn, httpProxy, httpPort, user, server, password);
}
}
public static final Creator<KimApn> CREATOR = new Creator<KimApn>() {
@Override
public KimApn createFromParcel(Parcel in) {
return new KimApn(in);
}
@Override
public KimApn[] newArray(int size) {
return new KimApn[size];
}
};
@Override
public String toString() {
return "KimApn{" +
"name='" + name + '\'' +
", apn='" + apn + '\'' +
", httpProxy='" + httpProxy + '\'' +
", httpPort='" + httpPort + '\'' +
", user='" + user + '\'' +
", server='" + server + '\'' +
", password='" + password + '\'' +
'}';
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeString(apn);
dest.writeString(httpProxy);
dest.writeString(httpPort);
dest.writeString(user);
dest.writeString(server);
dest.writeString(password);
}
public String getName() {
return name;
}
public String getApn() {
return apn;
}
public String getHttpProxy() {
return httpProxy;
}
public String getHttpPort() {
return httpPort;
}
public String getUser() {
return user;
}
public String getServer() {
return server;
}
public String getPassword() {
return password;
}
public KimApn(String name, String apn, String httpProxy, String httpPort, String user, String server, String password) {
this.name = name;
this.apn = apn;
this.httpProxy = httpProxy;
this.httpPort = httpPort;
this.user = user;
this.server = server;
this.password = password;
}
protected KimApn(Parcel in) {
readFromParcel(in);
}
public void readFromParcel (Parcel in) {
name = in.readString();
apn = in.readString();
httpProxy = in.readString();
httpPort = in.readString();
user = in.readString();
server = in.readString();
password = in.readString();
}
}
- 定義需要提供的aidl接口
IKimOpenApiManagerService
// IKimOpenApiManagerService.aidl
package com.kim.openapi;
// Declare any non-default types here with import statements
import com.kim.openapi.KimApn;
interface IKimOpenApiManagerService {
List<KimApn> getCurrentApnList();
int addApn(inout KimApn apn);
}
- 創(chuàng)建一個 Service 供客戶端遠程綁定
package com.kim.openapi;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import java.util.List;
public class KimOpenApiManagerService extends Service {
public KimOpenApiManagerService() {
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
return stub;
}
private IKimOpenApiManagerService.Stub stub = new IKimOpenApiManagerService.Stub() {
@Override
public List<KimApn> getCurrentApnList() throws RemoteException {
return null;
}
@Override
public int addApn(KimApn apn) throws RemoteException {
return -1;
}
};
}
- AndroidManifest.xml的修改
<service android:name="com.kim.openapi.KimOpenApiManagerService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="kim.openapi.action.start"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
6.將工程代碼抽離到rom中編譯,并賦予系統(tǒng)簽名與權(quán)限
7.客戶端(模仿第三方app調(diào)用)編碼
封裝aidl成jar或aar
到此步驟為止,只需要將上述aidl文件提供給客戶,即可完成第三方app通過api調(diào)用rom新增的功能接口。但是提供的aidl有可能會出現(xiàn)被誤修改等情況,為了避免這種情況,對aidl進行sdk封裝。
- 使用android studio 新建一個module ,類型為Android Library,包名任意
- 將server端工程的aidl文件夾直接復制到新的module下對應(yīng)位置,注意此處的包名路徑不能更改
image.png
- 編寫一個manager類,進行sdk封裝操作
package com.kim.openapi;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class KimOpenApiManager {
private static final String TAG = "KimOpenApiManager";
private Context mContext;
private IKimOpenApiManagerService mService;
private IBinder b;
private static KimOpenApiManager mInstance;
private boolean connected;
private KimOpenApiManager(Context context) {
mContext = context.getApplicationContext();
bindKimOpenApiManagerService(conn);
}
public void unRegister() {
if (connected) {
mContext.unbindService(conn);
}
}
public int addApn(KimApn apn) {
if (!connected) {
Log.e(TAG, "getService: connected= false");
}
int ret = 0;
try {
ret = getService().addApn(apn);
} catch (RemoteException e) {
e.printStackTrace();
}
return ret;
}
private IKimOpenApiManagerService getService() {
if (mService != null) {
return mService;
}
mService = IKimOpenApiManagerService.Stub.asInterface(b);
return mService;
}
public static synchronized KimOpenApiManager register(Context context) {
if (mInstance == null) {
mInstance = new KimOpenApiManager(context);
}
return mInstance;
}
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
b = service;
connected = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
connected = false;
}
};
private void bindKimOpenApiManagerService(ServiceConnection serviceConnection) {
Intent intent = new Intent();
intent.setPackage("com.kim.openapi");
intent.setAction("kim.openapi.action.start");
mContext.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
}
- 編譯module,生成aar和jar包(aar在outputs中,jar包生成的名字為classes.jar 各個版本生成位置不同,搜索即可)
- 三方app中對aar以及jar的引用
將文件添加到工程的libs文件夾下
5.1 如果是aar,在module中的build.gradle中android{}下添加
repositories {
flatDir {
dirs 'libs'
}
}
在dependencies{}下添加
implementation(name: 'aar 名稱不帶后綴', ext: 'aar')
5.2 如果是jar,右鍵->add as Library即可