1.插件 开发原理 Android
- 1.dart 注册
MethodChannel
和EventChannel
- 2.dart 中的
getPlatformVersion
通过_channel.invokeMethod
发起一次请求 - 3.原生Java代码中的
onMethodCall
方法会被调用- MethodCall call:请求本身
- Result result:结果处理方法
- 4.然后通过
call.method
可以知道_channel.invokeMethod
中的方法名,然后通过result.success
回调返回成功结果响应 - 5.新增方法:在onMethodCall中通过判断
call.method.equals
添加其他方法
2.插件 开发原理 iOS
- 1.dart 注册
MethodChannel
和EventChannel
- 2.dart 中的
getPlatformVersion
通过_channel.invokeMethod
发起一次请求 - 3.原生Objective-C代码中的
handleMethodCall
方法会被调用-
FlutterMethodCall call
:请求本身 -
FlutterResult result
:结果处理方法
-
- 4.然后通过
call.method
可以知道_channel.invokeMethod
中的方法名,然后通过result.success
回调返回成功结果响应 - 5.新增方法:在onMethodCall中通过判断
[@"xxx" isEqualToString:call.method]
添加其他方法
注意事项-采坑之旅
1.编码格式要统一
- iOS 端 和 Android 端编码格式要统一,解析方式NSArrray和NSDictionary对应Dart端List 和 Map 对应
- Android 端编码:
TIMCustomElem elem = new TIMCustomElem();
elem.setData(data.getBytes(Charset.forName("utf-8")));
- iOS 端编码:
TIMCustomElem *elem = [[TIMCustomElem alloc] init];
NSData *finalData = [data dataUsingEncoding:NSUTF8StringEncoding];
[elem setData:finalData];
2. 文本发送(sendTextMessages)
iOS端数据
{"timeStamp":1573473595,"message":{"text":"23333"},"uniqueId":0,"timConversation":{"type":0},"isSelf":true,"rand":1,"type":"Text","isRead":false,"seq":2,"sender":"46fac6aa8f6749335ed4ebb67061e72c","status":1,"msgId":"1030287601"}
缺少消息的类型,需要自己添加判断条件
解决办法:
在外层添加 type 字段,自己加入判断条件
// 获取消息类型
- (NSString *)getMessageType:(TIMMessage *)message{
if (message != nil){
int cnt = [message elemCount];
for (int i = 0; i < cnt; i ++) {
TIMElem * elem = [message getElem:i];
if ([elem isKindOfClass:[TIMTextElem class]]) {
return @"Text";
}else if ([elem isKindOfClass:[TIMImageElem class]]) {
return @"Image";
}else if ([elem isKindOfClass:[TIMSoundElem class]]) {
return @"Sound";
}else if ([elem isKindOfClass:[TIMCustomElem class]]) {
return @"Custom";
}else if ([elem isKindOfClass:[TIMFileElem class]]) {
return @"File";
}else if ([elem isKindOfClass:[TIMGroupTipsElem class]]) {
return @"GroupTips";
}else if ([elem isKindOfClass:[TIMFaceElem class]]) {
return @"Face";
}else if ([elem isKindOfClass:[TIMLocationElem class]]) {
return @"Location";
}else if ([elem isKindOfClass:[TIMGroupSystemElem class]]) {
return @"GroupSystem";
}else if ([elem isKindOfClass:[TIMSNSSystemElem class]]) {
return @"SNSTips";
}else if ([elem isKindOfClass:[TIMProfileSystemElem class]]) {
return @"ProfileTips";
}else if ([elem isKindOfClass:[TIMVideoElem class]]) {
return @"Video";
}else {
return @"Invalid";
}
}
}
return @"Invalid";
}
3.发送语音消息
-
Android 端
- 语音数组 urls
- 时长 duration
-
iOS 端语音数组
- 语音数组 soundUrls
- 时长 second
4.iOS 端添加错误信息回调(方便dart端异常捕获)
在失败的block中添加以下代码
result([FlutterError errorWithCode:[NSString stringWithFormat:@"%d",code] message:err details:@"im_login Failed"]);
成功回调
result(@"Login Succeed ~ ");
5.TIM 自定义消息解析
iOS 端 TIMMessage
(
"[2019-11-20 15:11:00][status:2 sender=2e3e14cad849d445f0334816b004de57]
[TIMCustomElem=data:<7b224d73 67547970 65223a22 4c696b65 5141222c
22436f6e 74656e74 223a7b22 71756573 74696f6e 223a7b22 6964223a 36393630 2c227469 746c6522 3a22e4bd a0e8aea4 e4b8bae4 b891e592
8ce7be8e e79a84e5 ae9ae4b9 89e698af e4bb80e4 b988227d 2c22616e 73776572 223a7b22 74797065 223a2274 65787422 2c227661 6c756522
3a226572 65777265 227d7d7d> desc: ext: sound:]"
)
转义处理
if ([[timMessage getElem:0] isKindOfClass:[TIMCustomElem class]]){
TIMCustomElem * emement = (TIMCustomElem*)[timMessage getElem:0];
NSString * str =[[NSString alloc] initWithData:emement.data encoding:NSUTF8StringEncoding];
NSLog(@"======customData>%@",str);
dimMessage.customData = str;
}
转义结果如下:
{"MsgType":"LikeQA","Content":{"question":{"id":8385,"title":"你认为丑和美的定义是什么"},"answer":{"type":"text","value":"wesad"}}}
转义字符处理
TIMConversation *conversation = [[TIMManager sharedInstance] getConversation:TIM_C2C receiver:identifier];
//发送消息
TIMMessage *customMsg = [[TIMMessage alloc] init];
TIMCustomElem *elem = [[TIMCustomElem alloc] init];
NSError *error = nil;
//自己写,不要完全相信demo,会坑死人。
NSString *jsonStr = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:data options:kNilOptions error:&error] encoding:NSUTF8StringEncoding];
jsonStr = [jsonStr stringByReplacingOccurrencesOfString:@"\\/" withString:@"/"];
jsonStr = [jsonStr stringByReplacingOccurrencesOfString:@"\\" withString:@""];
NSData *finalData = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];
if(error) {
NSLog(@"[%@] Post Json Error: %@", [self class], finalData);
return;
}
[elem setData:finalData];
Android 端自定义消息解析
{list_type: contact, friend_level: 1, last_at: 1574326174, last_msg: {timestamp: 1574326174, msgType: Custom, message: {
data: [123, 34, 77, 115, 103, 84, 121, 112, 101, 34, 58, 34, 76, 105, 107, 101,
68, 114, 97, 119, 34, 44, 34, 67, 111, 110, 116, 101, 110, 116, 34,
58, 123, 34, 112, 97, 105, 110, 116, 34, 58, 123, 34, 105, 100, 34, 58, 49, 57, 55, 44, 34, 117, 114, 108, 34, 58, 34, 104, 116, 116, 112, 115, 58, 47, 47, 111, 115, 115, 46, 112, 111, 99, 107, 101, 116, 117, 110, 105, 118, 101, 114, 115, 105, 116, 121, 46, 99, 110, 47, 109, 101, 100, 105, 97, 47, 50, 48, 49, 57, 45, 49, 49, 45, 50, 49, 47, 53, 100, 100, 54, 52, 102, 57, 99, 51, 101, 50, 48, 97, 46, 112, 110, 103, 34, 44, 34, 110, 97, 109,
101, 34, 58,34, 115, 100, 34, 125, 125, 125], desc: , type: Custom}, msgId: 37009186, seq: 1649340001, rand: 37009186, isSelf: true, uniqueId: 6761679430603814690, isRead: true, status: 2, timMessageLocator: {rand: 37009186, seq: 1649340001, timestamp: 1574326174, sid: null, isSelf: true}
转义Data
if (jsonData['data'] != null && !(jsonData['data'] is Map)) {
List<int> list = [];
jsonData['data'].forEach((data) {
list.add(data);
});
jsonData['data'] = jsonDecode(utf8.decode(Uint8List.fromList(list)));
}
补充
1.与原生交互API
// 与原生交互API
platformNavigator(BuildContext context) async {
if (Platform.isAndroid) {
if (window.defaultRouteName != '/') {
await SystemNavigator.pop();
return false;
} else {
Navigator.of(context).pop();
}
} else if (Platform.isIOS) {
try {
await platform.invokeMethod(PlatformCmd.NAVIGATOR_POP);
return false;
} on Exception catch (e) {
throw e;
}
}
}
platformShare(BuildContext context, String cmd) async {
if (window.defaultRouteName != '/') {
await platform.invokeMethod(cmd);
}else{
print(cmd);
}
}
platformGetInfo(BuildContext context,)async{
var user;
if (window.defaultRouteName != '/') {
user = await platform.invokeMethod(PlatformCmd.GET_INFO);
}else{
user = {'share_icon':'shutiao/common/share.jpg'};
}
return user;
}