HarmonyOS Sample 之 ServiceAbility 跨设备接口调用 原创 精华
@toc
ServiceAbility 跨设备接口调用
介绍
本示例演示了Service Ability的启动、停止、连接、断开连接等操作,支持对跨设备的Service Ability进行操作。
你将学会以下三个知识点:
1.IDL的使用,以及IPC方法的调用
2.前台Service的使用方法
3.EventHandle事件处理的使用方法
搭建环境
安装DevEco Studio,详情请参考DevEco Studio下载。
设置DevEco Studio开发环境,DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:
如果可以直接访问Internet,只需进行下载HarmonyOS SDK操作。
如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考配置开发环境。
代码结构解读
后台逻辑
│ config.json #全局配置文件
│
├─idl
│ └─ohos
│ └─samples
│ └─serviceability
│ IRemoteAgent.idl #提供远程接口idl文件
│
├─java
│ └─ohos
│ └─samples
│ └─serviceability
│ │ ForegroundServiceAbility.java #前台Service Ability
│ │ LocalServiceAbility.java #模拟本地的Service Ability
│ │ MainAbility.java
│ │ RemoteAbility.java #模拟远端的Service Ability
│ │
│ └─slice
│ MainAbilitySlice.java #主能力页
页面布局文件只有一个 main_slice.xml
页面布局
三个知识点
1.IDL的使用,以及IPC方法的调用
术语:
当客户端和服务器通信时,需要定义双方都认可的接口,以保障双方可以成功通信,HarmonyOS IDL(HarmonyOS Interface Definition Language)则是一种定义此类接口的工具。
跨进程调用(IPC)inter-process communication 或 跨设备调用(RPC)remote procedure call
IDL接口使用规范:
https://developer.harmonyos.com/cn/docs/documentation/doc-references/idl-overview-0000001050762835
先声明权限,同时敏感权限还需要请求用户授权,前几篇都有写过这里就不写了。
"reqPermissions": [
{
"name": "ohos.permission.GET_DISTRIBUTED_DEVICE_INFO"
},
...
{
"name": "ohos.permission.DISTRIBUTED_DATASYNC"
}
]
a.创建.idl文件
IRemoteAgent.idl
// Declare any non-default types here with sequenceable or interface statements
interface ohos.samples.serviceability.IRemoteAgent {
/*
* Demo service method use some parameters
*/
void setRemoteObject([in] String param);
}
b.编译idl文件,生成对应的接口类、桩类和代理类
c.服务端IDL的实现
private static final String DESCRIPTOR = "ohos.samples.serviceability.RemoteAbility";
//idl的服务端实现,
RemoteAgentStub remoteAgentStub = new RemoteAgentStub(DESCRIPTOR) {
@Override
public void setRemoteObject(String param) {
HiLog.info(LABEL_LOG, "%{public}s", "setRemoteObject:"+param);
//不能这样,要用下面通知的方式
//showTips(RemoteAbility.this, param);
//赋值
param_mess=param;
//事件通知
eventHandler.sendEvent(EVENT_ABILITY_MESS);
}
};
d.客户端调用IPC方法
//IDL代理类
private RemoteAgentProxy remoteAgentProxy;
/**
* 连接 Service
* @param isConnectRemote
*/
private void connectService(boolean isConnectRemote) {
//三元表达式,判断连接本地还是远端Service
Intent intent = isConnectRemote
? getRemoteServiceIntent(REMOTE_BUNDLE, REMOTE_SERVICE)
: getLocalServiceIntent(LOCAL_BUNDLE, NORMAL_SERVICE);
//连接 Service
boolean isConnect=connectAbility(intent,connection);
if (isConnect && remoteAgentProxy!=null) {
try {
//调用服务端IPC方法
remoteAgentProxy.setRemoteObject("This param from client");
} catch (RemoteException e) {
HiLog.error(LABEL_LOG, "%{public}s", "onAbilityConnectDone RemoteException");
}
}
}
//建立连接,实例化代理对象
private IAbilityConnection connection = new IAbilityConnection() {
@Override
public void onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int resultCode) {
//发个通知,Service 连接成功了
eventHandler.sendEvent(EVENT_ABILITY_CONNECT_DONE);
//实例化代理对象
remoteAgentProxy = new RemoteAgentProxy(iRemoteObject);
}
@Override
public void onAbilityDisconnectDone(ElementName elementName, int resultCode) {
//发个通知,Service 断开连接了,主动断开不会执行,关闭服务端会执行
eventHandler.sendEvent(EVENT_ABILITY_DISCONNECT_DONE);
}
};
2.前台Service的使用方法
a.权限声明:
"reqPermissions": [
{
"name": "ohos.permission.KEEP_BACKGROUND_RUNNING"
},
...
]
b.设置通知栏内容,然后,
在onStart方法调用keepBackgroundRunning方法在后台保留此服务能力并显示通知栏。
在onStop方法调用cancelBackgroundRunning()方法取消此功能的后台运行以释放系统内存。
//通知ID
private static final int NOTIFICATION_ID = 0XD0000002;
@Override
protected void onStart(Intent intent) {
//调用方法
startForeground();
super.onStart(intent);
}
@Override
protected void onStop() {
super.onStop();
//取消此功能的后台运行以释放系统内存。
cancelBackgroundRunning();
}
/**
* 在后台保留此服务能力并显示通知栏。
*/
private void startForeground() {
HiLog.info(LABEL_LOG, "startForeground");
//任务栏显示通知
NotificationRequest request = new NotificationRequest(NOTIFICATION_ID).setTapDismissed(true);
//
NotificationRequest.NotificationNormalContent content = new NotificationRequest.NotificationNormalContent();
content.setTitle("SD card存储卡已意外移除").setText("请先卸载存储卡,再将其移除,以防数据丢失");
content.setAdditionalText("21分钟前");
//设置通知栏内容
NotificationRequest.NotificationContent notificationContent = new NotificationRequest.NotificationContent(content);
request.setContent(notificationContent);
//在后台保留此服务能力并显示通知栏。
keepBackgroundRunning(NOTIFICATION_ID, request);
}
3.EventHandle事件处理的使用方法
EventHandler 将事件或 Runnable 任务传递到线程的事件队列,并在事件或任务从事件队列中出来时执行。
您可以使用 EventHandler 在不同线程之间调度和处理事件和 Runnable 对象,并在一定的时间间隔内安排要处理的事件或 Runnable 对象。您可以使用此类中提供的方法发送同步或异步事件、延迟事件处理以及设置事件优先级。
//定义事件ID
private static final int EVENT_ABILITY_CONNECT_DONE = 0x1000001;
private static final int EVENT_ABILITY_DISCONNECT_DONE = 0x1000002;
private EventHandler eventHandler = new EventHandler(EventRunner.current()) {
@Override
protected void processEvent(InnerEvent event) {
switch (event.eventId) {
case EVENT_ABILITY_CONNECT_DONE:
showTips(MainAbilitySlice.this, "Service connect succeeded");
break;
case EVENT_ABILITY_DISCONNECT_DONE:
showTips(MainAbilitySlice.this, "Service disconnect succeeded");
break;
default:
break;
}
}
};
//发个通知,Service 连接成功了
eventHandler.sendEvent(EVENT_ABILITY_CONNECT_DONE);
效果展示
前台Service | IPC/RPC调用 |
---|---|
完整代码
附件直接下载。
代码和演示都很详细,感谢楼主分享。
共同学习,希望对大家也能有一点点帮助!