En un ecosistema donde móviles, tablets, televisores y wearables conviven, la colave entre ellos no puede depender de protocolos propietarios ni de pasos manuales complejos. HarmonyOS resuelve este desafío mediante su capa de RPC distribuido y el Soft-Bus, que permiten que cualquier aplicación invoque funciones o consuma datos alojados en otro dispositivo como si se tratara de una llamada local.
Casos de uso típicos
- Smart Home: un teléfono detecta geolocalización y, al llegar a casa, enciende luces Philips, ajusta la temperatura del aire acondicionado Gree y cierra persianas Aqara, aunque cada fabricante haya compilado su propio hap.
- Productividad: un portátil ejecuta un IDE pesado, pero la previsualización de la app se renderiza en la tablet del diseñador vía streaming de superficies gráficas.
- Gaming: el mando es el smartphone; la GPU pesada corre en la consola; el audio sale por los auriculares del smartwatch. Los tres hablan por RPC sin latencia perceptible.
Activar el canal RPC + Soft-Bus
En config.json (o module.json a partir de API 12) basta con declarar:
"reqPermissions": [
{ "name": "ohos.permission.DISTRIBUTED_DATASYNC" },
{ "name": "ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE" }
]
El Soft-Bus se encarga de descubrimiento, emparejamiento y multiplexado de canales; el RPC driver gestiona la serialización binaria y la retransmisión ante pérdidas.
Identificando terminales con DeviceManager
Cada dispositivo posee un NetworkId único dentro del Super Device. El siguiente fragmento Java muestra cómo obtenerlo y suscribirse a eventos de red:
public final class DeviceRegistry {
private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00201, "DeviceRegistry");
private final DeviceManager mgr;
public DeviceRegistry(Context ctx) throws DeviceManagerException {
mgr = DeviceManager.getDeviceManager(ctx);
}
public String myNetworkId() throws DeviceManagerException {
return mgr.getLocalDevice().getNetworkId();
}
public void listen(Consumer<RemoteDevice> onUp, Consumer<RemoteDevice> onDown) {
DeviceManagerCallback callback = new DeviceManagerCallback() {
@Override public void onDeviceOnline(RemoteDevice d) { onUp.accept(d); }
@Override public void onDeviceOffline(RemoteDevice d) { onDown.accept(d); }
};
try { mgr.registerDeviceCallback(callback); }
catch (DeviceManagerException e) { HiLog.error(LABEL, "reg failed: %{public}s", e.getMessage()); }
}
}
Definiendo un servicio remoto
Primero creamos la interfaz IRemoteBroker con AIDL simplificado:
public interface ISumService extends IRemoteBroker {
int TRANSACTION_sum = IRemoteObject.FIRST_CALL_TRANSACTION;
int sum(int x, int y) throws RemoteException;
}
El stub del lado servidor:
public class SumServiceStub extends RemoteObject implements ISumService {
public SumServiceStub() { super("SumServiceStub"); }
@Override public int sum(int x, int y) { return x + y; }
@Override public boolean onRemoteRequest(int code, MessageParcel data,
MessageParcel reply, MessageOption option) {
if (code == TRANSACTION_sum) {
int x = data.readInt();
int y = data.readInt();
reply.writeInt(sum(x, y));
return true;
}
return super.onRemoteRequest(code, data, reply, option);
}
@Override public IRemoteObject asObject() { return this; }
}
Publicamos el servicio en el ServiceAbility:
@Override
protected IRemoteObject onConnect(Intent intent) {
return new SumServiceStub();
}
Cliente que invoca la operación remota
public class SumClient {
private final IRemoteObject remote;
public SumClient(IRemoteObject remote) { this.remote = remote; }
public int add(int a, int b) throws RemoteException {
MessageParcel data = MessageParcel.obtain();
MessageParcel reply = MessageParcel.obtain();
MessageOption option = new MessageOption(MessageOption.TF_SYNC);
try {
data.writeInt(a);
data.writeInt(b);
remote.sendRequest(ISumService.TRANSACTION_sum, data, reply, option);
return reply.readInt();
} finally {
data.reclaim();
reply.reclaim();
}
}
}
Para obtener el IRemoteObject del dispositivo destino:
IRemoteObject proxy = DeviceManager.getDeviceManager(context)
.getTrustedDeviceList()
.stream()
.filter(d -> d.getDeviceName().equals("MatePad"))
.findFirst()
.map(d -> connectAbility(intent, d.getNetworkId()))
.orElseThrow(() -> new RemoteException("Device not found"));
Diagrama simplificado del flujo
| Paso | Acción |
|---|---|
| 1 | Cliente descubre dispositivo y obtiene NetworkId |
| 2 | Cliente invoca connectAbility() a través del Soft-Bus |
| 3 | HarmonyOS resuelve la dirección lógica y abre canal seguro |
| 4 | Cliente empaqueta MessageParcel y llama sendRequest() |
| 5 | Servidor ejecuta onRemoteRequest() y devuelve resultado |
| 6 | RPC driver entrega respuesta; cliente des-serializa y continúa |
Con estos bloques se puede orquestar cualquier flujo multi-dispositivo: sincronizar bases de datos distribuidas, compartir lienzo gráfico, o delegar tareas pesadas al nodo más potente, todo sin que el usuario tenga que emparejar manualmente ni conocer direcciones IP.