Flutter iOS应用使用AWS Amplify创建用户设置失败问题排查
我正在开发一款基于AWS的Flutter iOS应用,当前遇到的问题是为用户添加持久化设置模型时出错。每个用户应对应一个由其选择项生成的设置模型,和常规应用逻辑一致。
具体来说,我需要一个名为randomPhotoOffset的布尔型设置项。有人建议我使用Amplify和DynamoDB存储用户设置,因为相比仅使用Cognito,它具备可扩展性且提供更多选项。
- 使用Amplify Gen 1及CLI
- amplify_flutter: ^2.6.0
- amplify_auth_cognito: ^2.5.0
- amplify_api: ^2.6.0
- amplify_datastore: ^2.6.0
- Flutter SDK: ^3.5.4(已更新
pubspec.yaml,所有包均为最新版本,无版本冲突)
测试环境:搭载M4 Pro芯片的Mac上的iPhone 16 Pro模拟器
点击按钮更改设置时会触发以下错误:
Exception updating user settings: ApiOperationException {
"message": "No modelProvider found",
"recoverySuggestion": "Pass in a modelProvider instance while instantiating APIPlugin"
}
main.dart
该函数在WidgetsFlutterBinding.ensureInitialized()之后、runApp()之前调用。
Future<void> configureAmplify() async { try { final authPlugin = AmplifyAuthCognito(); final apiPlugin = AmplifyAPI(); final dataStorePlugin = AmplifyDataStore(modelProvider: ModelProvider.instance); Amplify.addPlugins( [authPlugin, dataStorePlugin, apiPlugin], ); await Amplify.configure(amplifyConfig); // Start DataStore to register the model provider for GraphQL operations. await Amplify.DataStore.start(); } on Exception catch (e) { Log.e("Error configuring Amplify: $e"); } }
settings.dart
这是按钮点击时调用的唯一相关函数,切换后立即生效,无需保存按钮
Future<void> _toggleRandomPhotoOffset(bool newValue) async { setState(() { _randomPhotoOffset = newValue; }); try { // Retrieve the current user's ID from Amplify Auth. final authUser = await Amplify.Auth.getCurrentUser(); await updateUserSettings( userId: authUser.userId, randomPhotoOffset: newValue, ); } catch (e) { Log.e("Error retrieving user or updating settings: $e"); } }
settings_service.dart
updateUserSettings的定义如下
Future<void> updateUserSettings({ required String userId, required bool randomPhotoOffset, }) async { // Create a new UserSettings object. final settings = UserSettings( userId: userId, randomPhotoOffset: randomPhotoOffset, ); try { final request = ModelMutations.create(settings); final response = await Amplify.API.mutate(request: request).response; if (response.errors.isEmpty) { Log.i("User settings updated: ${response.data}"); } else { Log.e("Errors updating user settings: ${response.errors}"); } } catch (e) { Log.e("Exception updating user settings: $e"); } }
schema.graphql
这是Amplify所需的模型定义
type UserSettings @model { id: ID! userId: String! randomPhotoOffset: Boolean }
注:编写该模型后,我执行了amplify push和amplify codegen models,已成功生成ModelProvider.dart和UserSettings.dart,未对其进行任何修改。
方案1
尝试通过AI解决问题,但给出的方案不可行。例如建议修改settings_service如下:
Future<void> updateUserSettings({ required String userId, required bool randomPhotoOffset, }) async { final settings = UserSettings( userId: userId, randomPhotoOffset: randomPhotoOffset, ); try { final request = ModelMutations.create( settings, modelProvider: ModelProvider.instance, ); final response = await Amplify.API.mutate(request: request).response; if (response.errors.isEmpty) { print("User settings updated: ${response.data}"); } else { print("Errors updating user settings: ${response.errors}"); } } catch (e) { print("Exception updating user settings: $e"); } }
但ModelMutations.create并不支持modelProvider参数,问题仍未解决,我认为问题出在main.dart的配置中。
方案2
修改configureAmplify()为如下代码:
void _configureAmplify() async { try { final authPlugin = AmplifyAuthCognito(); final apiPlugin = AmplifyAPI(); Amplify.addPlugins([authPlugin, apiPlugin]); await Amplify.configure(amplifyconfig); setState(() { _amplifyConfigured = true; }); } catch (e) { print("Amplify configuration failed: $e"); } }
虽然没有语法错误,但上述错误仍会出现。
错误提示明确指出需要在实例化APIPlugin时传入modelProvider实例,当前代码中AmplifyAPI()初始化时未传入该参数,这就是问题根源。
步骤1:修正Amplify配置
修改main.dart中的configureAmplify函数,在创建AmplifyAPI时传入modelProvider:
Future<void> configureAmplify() async { try { final authPlugin = AmplifyAuthCognito(); // 传入ModelProvider.instance给APIPlugin final apiPlugin = AmplifyAPI(modelProvider: ModelProvider.instance); final dataStorePlugin = AmplifyDataStore(modelProvider: ModelProvider.instance); Amplify.addPlugins( [authPlugin, dataStorePlugin, apiPlugin], ); await Amplify.configure(amplifyConfig); await Amplify.DataStore.start(); } on Exception catch (e) { Log.e("Error configuring Amplify: $e"); } }
步骤2:优化设置更新逻辑
当前代码使用ModelMutations.create会每次生成新的UserSettings记录,建议先查询用户已有设置,存在则更新,不存在再创建,避免重复数据:
Future<void> updateUserSettings({ required String userId, required bool randomPhotoOffset, }) async { try { // 查询用户已有的设置记录 final query = ModelQueries.list(UserSettings.classType, UserSettings.USER_ID.eq(userId) ); final queryResponse = await Amplify.API.query(request: query).response; final existingSettings = queryResponse.data?.items; if (existingSettings != null && existingSettings.isNotEmpty) { // 更新已有记录 final updatedSettings = existingSettings.first.copyWith( randomPhotoOffset: randomPhotoOffset ); final updateRequest = ModelMutations.update(updatedSettings); final updateResponse = await Amplify.API.mutate(request: updateRequest).response; if (updateResponse.errors.isEmpty) { Log.i("User settings updated: ${updateResponse.data}"); } else { Log.e("Errors updating user settings: ${updateResponse.errors}"); } } else { // 创建新记录 final settings = UserSettings( userId: userId, randomPhotoOffset: randomPhotoOffset, ); final createRequest = ModelMutations.create(settings); final createResponse = await Amplify.API.mutate(request: createRequest).response; if (createResponse.errors.isEmpty) { Log.i("User settings created: ${createResponse.data}"); } else { Log.e("Errors creating user settings: ${createResponse.errors}"); } } } catch (e) { Log.e("Exception updating user settings: $e"); } }
内容的提问来源于stack exchange,提问作者user16208301

