Skip to content

Commit

Permalink
chore(api): API Native Bridge for .addPlugin() (#1756)
Browse files Browse the repository at this point in the history
  • Loading branch information
Equartey authored and Travis Sheppard committed Sep 26, 2022
1 parent c050eed commit 93203b1
Show file tree
Hide file tree
Showing 17 changed files with 526 additions and 65 deletions.
4 changes: 4 additions & 0 deletions packages/api/amplify_api/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.PHONY: pigeons
pigeons:
flutter pub run pigeon --input pigeons/native_api_plugin.dart
flutter format --fix lib/src/native_api_plugin.dart
3 changes: 2 additions & 1 deletion packages/api/amplify_api/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ dependencies:
sdk: flutter

dev_dependencies:
amplify_lints: ^2.0.0
amplify_lints:
path: ../../../amplify_lints
amplify_test:
path: ../../../amplify_test
flutter_driver:
Expand Down
21 changes: 6 additions & 15 deletions packages/api/amplify_api/lib/amplify_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@

library amplify_api_plugin;

import 'dart:io';

import 'package:amplify_api/src/method_channel_api.dart';
import 'package:amplify_api/src/api_plugin_impl.dart';
import 'package:amplify_core/amplify_core.dart';
import 'package:meta/meta.dart';

Expand All @@ -32,18 +30,11 @@ export './model_subscriptions.dart';
/// {@endtemplate}
abstract class AmplifyAPI extends APIPluginInterface {
/// {@macro amplify_api.amplify_api}
factory AmplifyAPI({
List<APIAuthProvider> authProviders = const [],
ModelProviderInterface? modelProvider,
}) {
if (zIsWeb || Platform.isWindows || Platform.isMacOS || Platform.isLinux) {
throw UnsupportedError('This platform is not supported yet');
}
return AmplifyAPIMethodChannel(
authProviders: authProviders,
modelProvider: modelProvider,
);
}
factory AmplifyAPI(
{List<APIAuthProvider> authProviders = const [],
ModelProviderInterface? modelProvider}) =>
AmplifyAPIDart(
authProviders: authProviders, modelProvider: modelProvider);

/// Protected constructor for subclasses.
@protected
Expand Down
81 changes: 81 additions & 0 deletions packages/api/amplify_api/lib/src/api_plugin_impl.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

library amplify_api;

import 'dart:io';

import 'package:amplify_api/amplify_api.dart';
import 'package:amplify_api/src/native_api_plugin.dart';
import 'package:amplify_core/amplify_core.dart';
import 'package:flutter/services.dart';

/// {@template amplify_api.amplify_api_dart}
/// The AWS implementation of the Amplify API category.
/// {@endtemplate}
class AmplifyAPIDart extends AmplifyAPI {
late final AWSApiPluginConfig _apiConfig;

/// The registered [APIAuthProvider] instances.
final Map<APIAuthorizationType, APIAuthProvider> _authProviders = {};

/// {@macro amplify_api.amplify_api_dart}
AmplifyAPIDart({
List<APIAuthProvider> authProviders = const [],
this.modelProvider,
}) : super.protected() {
authProviders.forEach(registerAuthProvider);
}

@override
Future<void> configure({AmplifyConfig? config}) async {
final apiConfig = config?.api?.awsPlugin;
if (apiConfig == null) {
throw const ApiException('No AWS API config found',
recoverySuggestion: 'Add API from the Amplify CLI. See '
'https://docs.amplify.aws/lib/graphqlapi/getting-started/q/platform/flutter/#configure-api');
}
_apiConfig = apiConfig;
}

@override
Future<void> addPlugin() async {
if (zIsWeb || !(Platform.isAndroid || Platform.isIOS)) {
return;
}

final nativeBridge = NativeApiBridge();
try {
final authProvidersList =
_authProviders.keys.map((key) => key.rawValue).toList();
await nativeBridge.addPlugin(authProvidersList);
} on PlatformException catch (e) {
if (e.code == 'AmplifyAlreadyConfiguredException') {
throw const AmplifyAlreadyConfiguredException(
AmplifyExceptionMessages.alreadyConfiguredDefaultMessage,
recoverySuggestion:
AmplifyExceptionMessages.alreadyConfiguredDefaultSuggestion);
}
throw AmplifyException.fromMap((e.details as Map).cast());
}
}

@override
final ModelProviderInterface? modelProvider;

@override
void registerAuthProvider(APIAuthProvider authProvider) {
_authProviders[authProvider.type] = authProvider;
}
}
63 changes: 63 additions & 0 deletions packages/api/amplify_api/lib/src/native_api_plugin.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// A copy of the License is located at
//
// http://aws.amazon.com/apache2.0
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.
//
// Autogenerated from Pigeon (v3.1.5), do not edit directly.
// See also: https://pub.dev/packages/pigeon
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name
// @dart = 2.12
import 'dart:async';
import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List;

import 'package:flutter/foundation.dart' show WriteBuffer, ReadBuffer;
import 'package:flutter/services.dart';

class _NativeApiBridgeCodec extends StandardMessageCodec {
const _NativeApiBridgeCodec();
}

class NativeApiBridge {
/// Constructor for [NativeApiBridge]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
NativeApiBridge({BinaryMessenger? binaryMessenger})
: _binaryMessenger = binaryMessenger;

final BinaryMessenger? _binaryMessenger;

static const MessageCodec<Object?> codec = _NativeApiBridgeCodec();

Future<void> addPlugin(List<String?> arg_authProvidersList) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.NativeApiBridge.addPlugin', codec,
binaryMessenger: _binaryMessenger);
final Map<Object?, Object?>? replyMap = await channel
.send(<Object?>[arg_authProvidersList]) as Map<Object?, Object?>?;
if (replyMap == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
} else if (replyMap['error'] != null) {
final Map<Object?, Object?> error =
(replyMap['error'] as Map<Object?, Object?>?)!;
throw PlatformException(
code: (error['code'] as String?)!,
message: error['message'] as String?,
details: error['details'],
);
} else {
return;
}
}
}
43 changes: 43 additions & 0 deletions packages/api/amplify_api/pigeons/native_api_plugin.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// A copy of the License is located at
//
// http://aws.amazon.com/apache2.0
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.
//

// ignore_for_file: avoid_positional_boolean_parameters

@ConfigurePigeon(
PigeonOptions(
copyrightHeader: '../../../tool/license.txt',
dartOptions: DartOptions(),
dartOut: 'lib/src/native_Api_plugin.dart',
javaOptions: JavaOptions(
className: 'NativeApiPluginBindings',
package: 'com.amazonaws.amplify.amplify_api',
),
javaOut:
'../amplify_api_android/android/src/main/kotlin/com/amazonaws/amplify/amplify_api/NativeApiPluginBindings.java',
objcOptions: ObjcOptions(
header: 'NativeApiPlugin.h',
),
objcHeaderOut: '../amplify_api_ios/ios/Classes/NativeApiPlugin.h',
objcSourceOut: '../amplify_api_ios/ios/Classes/NativeApiPlugin.m',
),
)
library native_api_plugin;

import 'package:pigeon/pigeon.dart';

@HostApi()
abstract class NativeApiBridge {
void addPlugin(List<String> authProvidersList);
}
10 changes: 9 additions & 1 deletion packages/api/amplify_api/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,22 @@ dependencies:
meta: ^1.7.0
plugin_platform_interface: ^2.0.0

dependency_overrides:
# TODO(dnys1): Remove when pigeon is bumped
# https://github.com/flutter/flutter/issues/105090
analyzer: ^3.0.0


dev_dependencies:
amplify_lints: ^2.0.0
amplify_lints:
path: ../../amplify_lints
amplify_test:
path: ../../amplify_test
build_runner: ^2.0.0
flutter_test:
sdk: flutter
mocktail: ^0.3.0
pigeon: ^3.1.5

# The following section is specific to Flutter.
flutter:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers

/** AmplifyApiPlugin */
class AmplifyApi : FlutterPlugin, MethodCallHandler {
class AmplifyApi : FlutterPlugin, MethodCallHandler, NativeApiPluginBindings.NativeApiBridge {

private companion object {
/**
Expand Down Expand Up @@ -83,6 +83,11 @@ class AmplifyApi : FlutterPlugin, MethodCallHandler {
"com.amazonaws.amplify/api_observe_events"
)
eventchannel!!.setStreamHandler(graphqlSubscriptionStreamHandler)

NativeApiPluginBindings.NativeApiBridge.setup(
flutterPluginBinding.binaryMessenger,
this
)
}

@Suppress("UNCHECKED_CAST")
Expand All @@ -94,27 +99,6 @@ class AmplifyApi : FlutterPlugin, MethodCallHandler {
if (methodName == "cancel") {
onCancel(result, (call.arguments as String))
return
} else if (methodName == "addPlugin") {
try {
val authProvidersList: List<String> =
(arguments["authProviders"] as List<*>?)?.cast() ?: listOf()
val authProviders = authProvidersList.map { AuthorizationType.valueOf(it) }
if (flutterAuthProviders == null) {
flutterAuthProviders = FlutterAuthProviders(authProviders)
}
flutterAuthProviders!!.setMethodChannel(channel)
Amplify.addPlugin(
AWSApiPlugin
.builder()
.apiAuthProviders(flutterAuthProviders!!.factory)
.build()
)
logger.info("Added API plugin")
result.success(null)
} catch (e: Exception) {
handleAddPluginException("API", e, result)
}
return
}

try {
Expand Down Expand Up @@ -168,5 +152,29 @@ class AmplifyApi : FlutterPlugin, MethodCallHandler {
eventchannel = null
graphqlSubscriptionStreamHandler?.close()
graphqlSubscriptionStreamHandler = null

NativeApiPluginBindings.NativeApiBridge.setup(
flutterPluginBinding.binaryMessenger,
null,
)
}

override fun addPlugin(authProvidersList: MutableList<String>) {
try {
val authProviders = authProvidersList.map { AuthorizationType.valueOf(it) }
if (flutterAuthProviders == null) {
flutterAuthProviders = FlutterAuthProviders(authProviders)
}
flutterAuthProviders!!.setMethodChannel(channel)
Amplify.addPlugin(
AWSApiPlugin
.builder()
.apiAuthProviders(flutterAuthProviders!!.factory)
.build()
)
logger.info("Added API plugin")
} catch (e: Exception) {
logger.error(e.message)
}
}
}
Loading

0 comments on commit 93203b1

Please sign in to comment.