Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/unify_uni_api/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 3.0.6

* feat: 在 UniFlutterModule 模式(native -> dart),新增 API 修饰注解 `@UniBufferSize(n)`,用于为指定方法对应的 platform channel 扩大消息缓冲区(默认容量为 1)。可解决原生在 Dart 侧 handler 注册前连续发消息时,早到消息被丢弃的问题。生成的原生 `setup` 会在建立 channel 时调用 `resizeChannelBuffer`(iOS)/`resizeChannelBuffer`(Android)。未标注的方法保持原有逻辑不变;`n` 必须为正整数字面量,非法值将告警并忽略;与 `@RequiredMessager` 同时标注时忽略并告警(目标 messenger 由每次调用决定)。
* fix: [iOS] UniAPI 生成的 OC 接口,基础类型(int/double/bool)统一装箱为 NSNumber*,与 Dart 声明类型不一致;改为映射为原生标量(NSInteger/double/BOOL)使参数与返回值类型对齐声明,可空类型及集合泛型实参位置仍回退 NSNumber*。同步修复 UniNativeModule / UniFlutterModule / UniCallback 三条通道中标量装箱/拆箱的胶水代码。
* fix: [iOS] 承接上条标量映射改动,修复 UniFlutterModule 回调路径的 ARC 报错:`UniCompleted` 回调形参为 `id`,而非空标量返回值被拆箱成 `NSInteger`/`BOOL`/`double` 后直接传入,触发 "Implicit conversion ... to 'id' is disallowed with ARC"。改为在目标为 `id` 时不拆箱,沿用 channel 传来的 NSNumber。

## 3.0.5

* fix: Flutter 与原生侧 UNICallback 的 key 名称不一致导致,UNICallback析构事件获取名称时 null,引发异常
Expand Down
24 changes: 24 additions & 0 deletions packages/unify_uni_api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,30 @@ Through this example, we experienced the value brought by Unify:
3. Automatic generation of a large number of channels, easy to maintain
4. Seamless serialization of complex entities, reducing management costs

## Advanced: Enlarging the Channel Buffer (`@UniBufferSize`)

In `@UniFlutterModule` mode (native -> dart), each platform channel keeps only **1** buffered message by default. If the native side sends messages *before* the Dart-side handler is registered (a common race during startup), earlier messages are silently dropped — e.g. calling a native->flutter method twice in a row may lose the first callback.

Annotate the method with `@UniBufferSize(n)` to enlarge that channel's buffer to `n`, so early messages are queued instead of discarded:

```dart
@UniFlutterModule()
abstract class LocationInfoService {
/// Enlarge this channel's buffer to 100.
@UniBufferSize(100)
void updateLocationInfo(LocationInfoModel model);
}
```

The generated native `setup` will size the buffer when the channel is created (iOS `resizeChannelBuffer:` / Android `resizeChannelBuffer(int)`).

Notes:

- Only effective in `@UniFlutterModule` mode (native -> dart).
- `n` must be a positive integer literal; invalid values are ignored with a warning.
- Methods without the annotation keep the original behavior unchanged (no code is generated).
- Ignored (with a warning) when combined with `@RequiredMessager`, since that method's target messenger is decided per call rather than at `setup` time.

## Decision Tree

We have summarized the following decision-making process:
Expand Down
24 changes: 24 additions & 0 deletions packages/unify_uni_api/README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,30 @@ OutlinedButton(
3. 大量 Channel 自动生成,易于维护
4. 复杂实体无缝序列化,降低管理成本

## 进阶:扩大 Channel 缓冲区(`@UniBufferSize`)

在 `@UniFlutterModule` 模式(native -> dart)下,每条 platform channel 默认只缓存 **1** 条消息。如果原生侧在 Dart 侧 handler 注册**之前**就发送消息(启动阶段常见的时序竞争),早到的消息会被静默丢弃 —— 例如连续两次调用某个 native->flutter 方法,可能丢掉第一次的回调。

给方法标注 `@UniBufferSize(n)`,即可将该 channel 的缓冲区扩大到 `n`,让早到消息进入队列而不是被丢弃:

```dart
@UniFlutterModule()
abstract class LocationInfoService {
/// 将该 channel 的缓冲区扩大到 100。
@UniBufferSize(100)
void updateLocationInfo(LocationInfoModel model);
}
```

生成的原生 `setup` 会在创建 channel 时设置缓冲区大小(iOS `resizeChannelBuffer:` / Android `resizeChannelBuffer(int)`)。

说明:

- 仅在 `@UniFlutterModule` 模式(native -> dart)下生效。
- `n` 必须为正整数字面量;非法值会告警并忽略。
- 未标注的方法保持原有逻辑不变(不生成任何代码)。
- 与 `@RequiredMessager` 同时标注时忽略并告警,因为该方法的目标 messenger 由每次调用决定,而非在 `setup` 时确定。

## Decision Tree

我们总结了如下决策流程:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// =================================================
// Autogenerated from Unify 3.0.4, do not edit directly.
// Autogenerated from Unify 3.0.6, do not edit directly.
// =================================================

package com.example.uninativemodule_demo;
Expand All @@ -17,6 +17,8 @@ public class DeviceInfoModel extends UniModel {
private String osVersion; // 系统版本
private String memory; // 内存信息
private String plaform; // 手机型号
private long test;
private boolean test2;

public String getOsVersion() { return osVersion; }

Expand All @@ -30,13 +32,23 @@ public class DeviceInfoModel extends UniModel {

public void setPlaform(String plaform) { this.plaform = plaform; }

public long getTest() { return test; }

public void setTest(long test) { this.test = test; }

public boolean getTest2() { return test2; }

public void setTest2(boolean test2) { this.test2 = test2; }


@Override
public Map<String, Object> toMap() {
Map<String, Object> result = new HashMap<>();
result.put("osVersion", osVersion);
result.put("memory", memory);
result.put("plaform", plaform);
result.put("test", test);
result.put("test2", test2);
return result;
}

Expand All @@ -45,6 +57,8 @@ public static DeviceInfoModel fromMap(Map<String, Object> map) {
result.osVersion = map.containsKey("osVersion") && map.get("osVersion") != null ? (String) map.get("osVersion") : "";
result.memory = map.containsKey("memory") && map.get("memory") != null ? (String) map.get("memory") : "";
result.plaform = map.containsKey("plaform") && map.get("plaform") != null ? (String) map.get("plaform") : "";
result.test = map.containsKey("test") && map.get("test") != null ? ((Number) map.get("test")).longValue() : 0;
result.test2 = map.containsKey("test2") && map.get("test2") != null ? (Boolean) map.get("test2") : false;
return result;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// =================================================
// Autogenerated from Unify 3.0.4, do not edit directly.
// Autogenerated from Unify 3.0.6, do not edit directly.
// =================================================

package com.example.uninativemodule_demo;
Expand Down Expand Up @@ -27,4 +27,14 @@ interface Result<T> {
*/
void getDeviceInfo(Result<DeviceInfoModel> result);

long test(boolean st);

boolean test2(double st);

String test3(long st);

long test4(long st);

void test5(Map<String, Long> st, Result<Long> result);

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// =================================================
// Autogenerated from Unify 3.0.4, do not edit directly.
// Autogenerated from Unify 3.0.6, do not edit directly.
// =================================================

package com.example.uninativemodule_demo;
Expand Down Expand Up @@ -85,7 +85,137 @@ public static void setup(BinaryMessenger binaryMessenger, DeviceInfoService impl
Map<String, Object> params = (Map<String, Object>) message;
impl.getDeviceInfo((ret) -> {
try {
wrapped.put("result", ret.toMap());
if (ret == null) {
wrapped.put("result", null);
} else {
wrapped.put("result", ret.toMap());
}
reply.reply(wrapped);
} catch (Error | RuntimeException exception) {
wrapped.put("error", wrapError(exception));
reply.reply(wrapped);
Log.d("flutter", "error: " + exception);
}
});
} catch (Error | RuntimeException exception) {
wrapped.put("error", wrapError(exception));
reply.reply(wrapped);
Log.d("flutter", "error: " + exception);
}
});
} else {
channel.setMessageHandler((message, reply) -> {});
}
}
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(binaryMessenger, "com.didi.flutter.uni_api.DeviceInfoService.test", new StandardMessageCodec());
if (impl != null) {
UDUniAPI.registerModule(impl);
channel.setMessageHandler((message, reply) -> {
Map<String, Object> wrapped = new HashMap<>();
try {
Map<String, Object> params = (Map<String, Object>) message;
boolean st = params.containsKey("st") ? (boolean) params.get("st") : false;
long output = impl.test(st);
wrapped.put("result", output);
} catch (Error | RuntimeException exception) {
wrapped.put("error", wrapError(exception));
Log.d("flutter", "error: " + exception);
} finally {
reply.reply(wrapped);
}
});
} else {
channel.setMessageHandler((message, reply) -> {});
}
}
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(binaryMessenger, "com.didi.flutter.uni_api.DeviceInfoService.test2", new StandardMessageCodec());
if (impl != null) {
UDUniAPI.registerModule(impl);
channel.setMessageHandler((message, reply) -> {
Map<String, Object> wrapped = new HashMap<>();
try {
Map<String, Object> params = (Map<String, Object>) message;
double st = params.containsKey("st") ? (double) params.get("st") : 0.0;
boolean output = impl.test2(st);
wrapped.put("result", output);
} catch (Error | RuntimeException exception) {
wrapped.put("error", wrapError(exception));
Log.d("flutter", "error: " + exception);
} finally {
reply.reply(wrapped);
}
});
} else {
channel.setMessageHandler((message, reply) -> {});
}
}
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(binaryMessenger, "com.didi.flutter.uni_api.DeviceInfoService.test3", new StandardMessageCodec());
if (impl != null) {
UDUniAPI.registerModule(impl);
channel.setMessageHandler((message, reply) -> {
Map<String, Object> wrapped = new HashMap<>();
try {
Map<String, Object> params = (Map<String, Object>) message;
long st = params.containsKey("st") ? ((Number) params.get("st")).longValue() : 0;
String output = impl.test3(st);
wrapped.put("result", output);
} catch (Error | RuntimeException exception) {
wrapped.put("error", wrapError(exception));
Log.d("flutter", "error: " + exception);
} finally {
reply.reply(wrapped);
}
});
} else {
channel.setMessageHandler((message, reply) -> {});
}
}
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(binaryMessenger, "com.didi.flutter.uni_api.DeviceInfoService.test4", new StandardMessageCodec());
if (impl != null) {
UDUniAPI.registerModule(impl);
channel.setMessageHandler((message, reply) -> {
Map<String, Object> wrapped = new HashMap<>();
try {
Map<String, Object> params = (Map<String, Object>) message;
long st = params.containsKey("st") ? ((Number) params.get("st")).longValue() : 0;
long output = impl.test4(st);
wrapped.put("result", output);
} catch (Error | RuntimeException exception) {
wrapped.put("error", wrapError(exception));
Log.d("flutter", "error: " + exception);
} finally {
reply.reply(wrapped);
}
});
} else {
channel.setMessageHandler((message, reply) -> {});
}
}
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(binaryMessenger, "com.didi.flutter.uni_api.DeviceInfoService.test5", new StandardMessageCodec());
if (impl != null) {
UDUniAPI.registerModule(impl);
channel.setMessageHandler((message, reply) -> {
Map<String, Object> wrapped = new HashMap<>();
try {
Map<String, Object> params = (Map<String, Object>) message;
Map<String, Long> st = params.containsKey("st") ? (Map<String, Long>) params.get("st") : new HashMap<>();
impl.test5(st, (ret) -> {
try {
if (ret == null) {
wrapped.put("result", null);
} else {
wrapped.put("result", ret);
}
reply.reply(wrapped);
} catch (Error | RuntimeException exception) {
wrapped.put("error", wrapError(exception));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
// =================================================
// Autogenerated from Unify 3.0.4, do not edit directly.
// Autogenerated from Unify 3.0.6, do not edit directly.
// =================================================

package com.example.uninativemodule_demo;

import java.util.HashMap;
import java.util.Map;

import io.flutter.plugin.common.BinaryMessenger;

public class UDUniAPI {
private static boolean isInit = false;
public static Map<String, Object> moduleMap = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// =================================================
// Autogenerated from Unify 3.0.4, do not edit directly.
// Autogenerated from Unify 3.0.6, do not edit directly.
// =================================================

package com.example.uninativemodule_demo;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// =================================================
// Autogenerated from Unify 3.0.4, do not edit directly.
// Autogenerated from Unify 3.0.6, do not edit directly.
// =================================================

package com.example.uninativemodule_demo;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// =================================================
// Autogenerated from Unify 3.0.4, do not edit directly.
// Autogenerated from Unify 3.0.6, do not edit directly.
// =================================================

package com.example.uninativemodule_demo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,24 @@ - (NSString *)getTotalMemorySize {
else if (fileSize < GB)return [NSString stringWithFormat:@"%.2f MB",((CGFloat)fileSize)/MB];
else return [NSString stringWithFormat:@"%.2f GB",((CGFloat)fileSize)/GB];
}

- (NSInteger)test:(BOOL)st error:(FlutterError *_Nullable *_Nonnull)error {
NSLog(@"test - %d",st);
return 999;
}

- (BOOL)test2:(double)st error:(FlutterError *_Nullable *_Nonnull)error {
NSLog(@"test2 - %f",st);
return YES;
}

- (NSString*)test3:(NSInteger)st error:(FlutterError *_Nullable *_Nonnull)error {
NSLog(@"test3 - %ld",(long)st);
return @"test3";
}

- (NSNumber*)test4:(NSInteger)st error:(FlutterError *_Nullable *_Nonnull)error {
NSLog(@"test4 - %ld",(long)st);
return @(-1000);
}
@end
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,42 @@ class _MyAppState extends State<MyApp> {
});
},
),
Text('test\n'),
OutlinedButton(
child: const Text("test"),
onPressed: () {
DeviceInfoService.test(false).then((deviceInfoModel) {
print('test - $deviceInfoModel');
});
},
),
Text('test2\n'),
OutlinedButton(
child: const Text("test2"),
onPressed: () {
DeviceInfoService.test2(9.999).then((deviceInfoModel) {
print('test - $deviceInfoModel');
});
},
),
Text('test3\n'),
OutlinedButton(
child: const Text("test"),
onPressed: () {
DeviceInfoService.test3(3000).then((deviceInfoModel) {
print('test - $deviceInfoModel');
});
},
),
Text('test4\n'),
OutlinedButton(
child: const Text("test4"),
onPressed: () {
DeviceInfoService.test4(4000).then((deviceInfoModel) {
print('test - $deviceInfoModel');
});
},
),
],)
),
),
Expand Down
Loading