Original README snapshot from the linked source repository. Visit the repository for the latest content.
Deeplink RPC
A RPC-via-deeplink communication library coded in Dart.
This is dedicated to Flutter mobile applications (iOS / Android).
Protocol
Deeplink codec
Deeplink messages are appended to the deeplink URI. Because of that, there are limitations in the available formatting.
To get it working, the message is encoded that way :
+--------------+ +------+ +-----------+
method_payload : | Json Message |-> | gzip |-> | base64Url |
+--------------+ +------+ +-----------+
Deeplink Url : `<scheme>:
Example :
+--------------------------+ +----------------------------------------------------------------+
method_payload : | { "param1" : "a_value" } |----> | "H4sIAAAAAAAAA6tWUCpILErMNVRSsFJQSowvS8wpTVVSqAUAhIgKchgAAAA=" |
+--------------------------+ +----------------------------------------------------------------+
Deeplink Url : `scheme:
Request formatting
Requests payload are encapsulated in a JSON-RPC 2.0 message.
{
"id": Number,
"replyUrl": String,
"params": {
"origin": {
"name": String,
"url": String | undefined,
"logo": Base64 | undefined,
},
"version": 2,
"payload": Object,
}
}
Success Response formatting
{
"id": Number,
"result": Object,
}
Failure Response formatting
{
"id": Number,
"failure": {
"code": Number,
"message": String | undefined,
"data": Object | undefined,
},
}
Usage
Server - listening to incoming requests
final _deeplinkRpcServer = DeeplinkRpcServer()
..registerHandler(
DeeplinkRpcRequestHandler(
route: const DeeplinkRpcRoute('a_rpc_command'),
handle: (request) {
log('Command received');
}
),
);
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'DeeplinkRPC Demo',
home: const SendForm(),
onGenerateRoute: (settings) {
if (_deeplinkRpcServer.handleRoute(settings.name)) return;
return null;
},
);
}
}
Client - Sending requests and listening for responses
final _deeplinkRpcClient = DeeplinkRpcClient();
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'DeeplinkRPC Demo',
onGenerateRoute: (settings) {
if (_deeplinkRpcClient.handleRoute(settings.name)) return;
return null;
},
home: Scaffold(
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.send),
onPressed: () async {
final response = await _deeplinkRpcClient.send(
timeout: const Duration(seconds: 5),
request: DeeplinkRpcRequest(
requestUrl: 'serverapp://server.app/request_endpoint',
replyUrl: 'clientapp://client.app/reply_endpoint',
params: {
'param1': 'value1',
'param2': 'value2',
},
),
);
response.map(
failure: (failure) {
log(
'RPC request failed',
error: failure,
);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(failure.message ?? "An error occured")),
);
},
success: (result) {
log(
'RPC request succeed : ${json.encode(result)}',
);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(json.encode(result))),
);
},
);
},
),
body: const SafeArea(
child: Padding(
padding: EdgeInsets.all(8.0),
child: Center(
child: Text('Client example'),
),
),
),
),
);
}
}