Skip to content

Commit ec31654

Browse files
authored
[pigeon] Added the ability for objc to return errors. (#113)
1 parent 362dde3 commit ec31654

7 files changed

Lines changed: 96 additions & 10 deletions

File tree

packages/pigeon/example/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ flutter pub run pigeon \
4242
@end
4343

4444
@implementation MyApi
45-
-(SearchReply*)search:(SearchRequest*)request {
45+
-(SearchReply*)search:(SearchRequest*)request error:(FlutterError **)error {
4646
SearchReply *reply = [[SearchReply alloc] init];
4747
reply.result =
4848
[NSString stringWithFormat:@"Hi %@!", request.query];

packages/pigeon/lib/dart_generator.dart

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,18 @@ void _writeHostApi(Indent indent, Api api) {
2222
'BasicMessageChannel(\'$channelName\', StandardMessageCodec());');
2323
indent.dec();
2424
indent.dec();
25-
indent.writeln('Map replyMap = await channel.send(requestMap);');
26-
indent.writeln('return ${func.returnType}._fromMap(replyMap);');
25+
indent.writeln('');
26+
indent.format('''Map replyMap = await channel.send(requestMap);
27+
if (replyMap['error'] != null) {
28+
\tMap error = replyMap['${Keys.error}'];
29+
\tthrow PlatformException(
30+
\t\t\tcode: error['${Keys.errorCode}'],
31+
\t\t\tmessage: error['${Keys.errorMessage}'],
32+
\t\t\tdetails: error['${Keys.errorDetails}']);
33+
} else {
34+
\treturn ${func.returnType}._fromMap(replyMap[\'${Keys.result}\']);
35+
}
36+
''');
2737
});
2838
}
2939
});

packages/pigeon/lib/generator_tools.dart

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ class Indent {
3131
/// String used for newlines (ex "\n").
3232
final String newline = '\n';
3333

34+
/// String used to represent a tab.
35+
final String tab = ' ';
36+
3437
/// Increase the indentation level.
3538
void inc() {
3639
_count += 1;
@@ -45,11 +48,18 @@ class Indent {
4548
String str() {
4649
String result = '';
4750
for (int i = 0; i < _count; i++) {
48-
result += ' ';
51+
result += tab;
4952
}
5053
return result;
5154
}
5255

56+
/// Replaces the newlines and tabs of input and adds it to the stream.
57+
void format(String input) {
58+
for (String line in input.split('\n')) {
59+
writeln(line.replaceAll('\t', tab));
60+
}
61+
}
62+
5363
/// Scoped increase of the ident level. For the execution of [func] the
5464
/// indentation will be incremented.
5565
void scoped(String begin, String end, Function func) {
@@ -126,3 +136,21 @@ const String generatedCodeWarning =
126136

127137
/// String to be printed after `generatedCodeWarning`.
128138
const String seeAlsoWarning = 'See also: https://pub.dev/packages/pigeon';
139+
140+
/// Collection of keys used in dictionaries across generators.
141+
class Keys {
142+
/// The key in the result hash for the 'result' value.
143+
static const String result = 'result';
144+
145+
/// The key in the result hash for the 'error' value.
146+
static const String error = 'error';
147+
148+
/// The key in an error hash for the 'code' value.
149+
static const String errorCode = 'code';
150+
151+
/// The key in an error hash for the 'message' value.
152+
static const String errorMessage = 'message';
153+
154+
/// The key in an error hash for the 'details' value.
155+
static const String errorDetails = 'details';
156+
}

packages/pigeon/lib/java_generator.dart

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,21 @@ void _writeHostApi(Indent indent, Api api) {
6262
final String returnType = method.returnType;
6363
indent.writeln(
6464
'$argType input = $argType.fromMap((HashMap)message);');
65-
indent.writeln('$returnType output = api.${method.name}(input);');
66-
indent.writeln('reply.reply(output.toMap());');
65+
indent.writeln(
66+
'HashMap<String, HashMap> wrapped = new HashMap<String, HashMap>();');
67+
indent.write('try ');
68+
indent.scoped('{', '}', () {
69+
indent
70+
.writeln('$returnType output = api.${method.name}(input);');
71+
indent
72+
.writeln('wrapped.put("${Keys.result}", output.toMap());');
73+
});
74+
indent.write('catch (Exception exception) ');
75+
indent.scoped('{', '}', () {
76+
indent.writeln(
77+
'wrapped.put("${Keys.error}", wrapError(exception));');
78+
});
79+
indent.writeln('reply.reply(wrapped);');
6780
});
6881
});
6982
});
@@ -200,5 +213,13 @@ void generateJava(JavaOptions options, Root root, StringSink sink) {
200213
_writeFlutterApi(indent, api);
201214
}
202215
}
216+
217+
indent.format('''private static HashMap wrapError(Exception exception) {
218+
\tHashMap<String, Object> errorMap = new HashMap<String, Object>();
219+
\terrorMap.put("${Keys.errorMessage}", exception.toString());
220+
\terrorMap.put("${Keys.errorCode}", null);
221+
\terrorMap.put("${Keys.errorDetails}", null);
222+
\treturn errorMap;
223+
}''');
203224
});
204225
}

packages/pigeon/lib/objc_generator.dart

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ void generateObjcHeader(ObjcOptions options, Root root, StringSink sink) {
6969
indent.writeln('// $seeAlsoWarning');
7070
indent.writeln('#import <Foundation/Foundation.h>');
7171
indent.writeln('@protocol FlutterBinaryMessenger;');
72+
indent.writeln('@class FlutterError;');
7273
indent.writeln('@class FlutterStandardTypedData;');
7374
indent.writeln('');
7475

@@ -104,7 +105,8 @@ void generateObjcHeader(ObjcOptions options, Root root, StringSink sink) {
104105
for (Method func in api.methods) {
105106
final String returnType = _className(options.prefix, func.returnType);
106107
final String argType = _className(options.prefix, func.argType);
107-
indent.writeln('-($returnType *)${func.name}:($argType*)input;');
108+
indent.writeln(
109+
'-($returnType *)${func.name}:($argType*)input error:(FlutterError **)error;');
108110
}
109111
indent.writeln('@end');
110112
indent.writeln('');
@@ -175,8 +177,10 @@ void _writeHostApiSource(Indent indent, ObjcOptions options, Api api) {
175177
final String returnType =
176178
_className(options.prefix, func.returnType);
177179
indent.writeln('$argType *input = [$argType fromMap:message];');
178-
indent.writeln('$returnType *output = [api ${func.name}:input];');
179-
indent.writeln('callback([output toMap]);');
180+
indent.writeln('FlutterError *error;');
181+
indent.writeln(
182+
'$returnType *output = [api ${func.name}:input error:&error];');
183+
indent.writeln('callback(wrapResult([output toMap], error));');
180184
});
181185
});
182186
indent.write('else ');
@@ -247,6 +251,28 @@ void generateObjcSource(ObjcOptions options, Root root, StringSink sink) {
247251
indent.writeln('#import <Flutter/Flutter.h>');
248252
indent.writeln('');
249253

254+
indent.writeln('#if !__has_feature(objc_arc)');
255+
indent.writeln('#error File requires ARC to be enabled.');
256+
indent.writeln('#endif');
257+
indent.addln('');
258+
259+
indent.format(
260+
'''static NSDictionary* wrapResult(NSDictionary *result, FlutterError *error) {
261+
\tNSDictionary *errorDict = (NSDictionary *)[NSNull null];
262+
\tif (error) {
263+
\t\terrorDict = [NSDictionary dictionaryWithObjectsAndKeys:
264+
\t\t\t\t(error.code ? error.code : [NSNull null]), @"${Keys.errorCode}",
265+
\t\t\t\t(error.message ? error.message : [NSNull null]), @"${Keys.errorMessage}",
266+
\t\t\t\t(error.details ? error.details : [NSNull null]), @"${Keys.errorDetails}",
267+
\t\t\t\tnil];
268+
\t}
269+
\treturn [NSDictionary dictionaryWithObjectsAndKeys:
270+
\t\t\t(result ? result : [NSNull null]), @"${Keys.result}",
271+
\t\t\terrorDict, @"${Keys.error}",
272+
\t\t\tnil];
273+
}''');
274+
indent.addln('');
275+
250276
for (Class klass in root.classes) {
251277
final String className = _className(options.prefix, klass.name);
252278
indent.writeln('@interface $className ()');

packages/pigeon/run_tests.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ test_pigeon_ios() {
1919
-isysroot $(xcrun --sdk iphoneos --show-sdk-path) \
2020
-F $framework_path \
2121
-Werror \
22+
-fobjc-arc \
2223
-c $temp_dir/pigeon.m \
2324
-o $temp_dir/pigeon.o
2425

packages/pigeon/test/objc_generator_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ void main() {
5252
expect(code, contains('@interface Input'));
5353
expect(code, contains('@interface Output'));
5454
expect(code, contains('@protocol Api'));
55-
expect(code, matches('Output.*doSomething.*Input'));
55+
expect(code, matches('Output.*doSomething.*Input.*FlutterError'));
5656
expect(code, contains('ApiSetup('));
5757
});
5858

0 commit comments

Comments
 (0)