0

我的 pubspec.yaml

dev_dependencies:
  flutter_test:
    sdk: flutter
  graphql_flutter: ^4.0.0

roomctrl.dart

import 'package:flutter/material.dart';
import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:innospace/config/appsync-service.dart';
import 'package:innospace/config/client_provider.dart';

class RoomCtrl extends StatefulWidget {
  RoomCtrl({Key key}) : super(key: key);

  _RoomCtrlState createState() => _RoomCtrlState();
}

class _RoomCtrlState extends State<RoomCtrl> {

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return ClientProvider(
        child: Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: <Widget>[
         Subscription(
        options:SubscriptionOptions(
            document: gql(AppSyncService.onUpdateStateTestSubscription)),
          builder: (result) {
            if (result.hasException) {
              return Text(result.exception.toString());
            }

            if (result.isLoading) {
              return Center(
                child: const CircularProgressIndicator(),
              );
            }
            return Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: <Widget>[
                  Container(
                    child: Text(result.data.length.toString()),
                  )
                ],
              ),
            );
          },
        )

          ],
        ),
      ),
    ));
  }
}

client_provider.dart

import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:flutter/material.dart';

import 'constants.dart';

String uuidFromObject(Object object) {
  if (object is Map<String, Object>) {
    final String typeName = object['__typename'] as String;
    final String id = object['id'].toString();
    if (typeName != null && id != null) {
      return <String>[typeName, id].join('/');
    }
  }
  return null;
}

ValueNotifier<GraphQLClient> clientFor() {
   const dynamic headers = {
    "headers": {
      "host": AWS_APP_SYNC_ENDPOINT_AUTHORITY,
      "x-api-key": AWS_APP_SYNC_KEY
    }};
   const  sClient= SocketClientConfig(
      autoReconnect : true,
      initialPayload: headers
  );

   final WebSocketLink _webSocketLink =new WebSocketLink(AWS_APP_SYNC_ENDPOINT_WSS,  config:sClient );

   final Link link = _webSocketLink;
  return ValueNotifier<GraphQLClient>(
    GraphQLClient(
      cache: GraphQLCache(),
      link: link,
    ),
  );
}

/// Wraps the root application with the `graphql_flutter` client.
/// We use the cache for all state management.
class ClientProvider extends StatelessWidget {
  ClientProvider({
    @required this.child,
  }) : client = clientFor();

  final Widget child;
  final ValueNotifier<GraphQLClient> client;

  @override
  Widget build(BuildContext context) {
    return GraphQLProvider(
      client: client,
      child: child,
    );
  }
}

常量.dart

[https://docs.aws.amazon.com/appsync/latest/devguide/real-time-websocket-client.html][1]

const AWS_APP_SYNC_ENDPOINT_AUTHORITY = "xxxxxxxxxxxxxxxxxxxxx.appsync-api.ap-southeast-2.amazonaws.com"; 
const AWS_APP_SYNC_ENDPOINT_WSS = "wss://xxxxxxxxxxxxxxxxxxxxx.appsync-realtime-api.ap-southeast-2.amazonaws.com/graphql?header=base64encryption(xxx-xxxxxxxxxxxxxxxxxx as per aws)&payload=e30="; 
const AWS_APP_SYNC_KEY = "xxx-xxxxxxxxxxxxxxxxxx";

订阅查询

static String onUpdateStateTestSubscription = '''
        subscription OnUpdateStateTest {
        onUpdateStateTest {
          __typename
          RoomId
          RoomName
        }
      }''';

安慰

Connecting to websocket: wss://xxxxxxxxxxxxxxxxxxxxx.appsync-realtime-api.ap-southeast-2.amazonaws.com/graphql?header=base64encryption(xxx-xxxxxxxxxxxxxxxxxx as per aws)&payload=e30=...
I/flutter ( 9942): Connected to websocket.
I/flutter ( 9942): Haven't received keep alive message for 30 seconds. Disconnecting..
I/flutter ( 9942): Disconnected from websocket.
I/flutter ( 9942): Scheduling to connect in 5 seconds...
I/flutter ( 9942): Connecting to websocket: wss://xxxxxxxxxxxxxxxxxxxxx.appsync-realtime-api.ap-southeast-2.amazonaws.com/graphql?header=base64encryption(xxx-xxxxxxxxxxxxxxxxxx as per aws)&payload=e30=...
I/flutter ( 9942): Connected to websocket.
I/flutter ( 9942): Haven't received keep alive message for 30 seconds. Disconnecting..
I/flutter ( 9942): Disconnected from websocket.
I/flutter ( 9942): Scheduling to connect in 5 seconds...

最后在移动设备上的输出显示正在加载 gif,即 CircularProgressIndicator(),意味着在“if (result.isLoading)”处始终返回 true

[![在此处输入图像描述][2]][2]

谁能帮忙!!

注意:相同的 appsync 在 Angular 应用程序中完美运行。[1]:https ://docs.aws.amazon.com/appsync/latest/devguide/real-time-websocket-client.html [2]:https ://i.stack.imgur.com/59KZh.png

4

2 回答 2

4

在底部查看我最近的更新。

我实际上遇到了同样的问题。我没有完整的答案,但我觉得这是部分答案的线索。

从链接

据我所知,AppSync 不使用 wss://<your_end_point>。我以前试过这个,我的http连接从来没有“升级到wss”连接。我必须向请求订阅连接的 http 端点发布请求,然后 AWS 返回包含新端点(wss url)、主题和客户端 ID 的连接详细信息。只有这样我才能使用第三方库(使用 AWS 返回的 URL)连接到套接字。我不得不深入研究他们的官方 sdk 来找出这个问题,然后通过反复试验让它工作。

我已使用 GraphiQL 工具确认,当我发布订阅 graphql blob 时确实会收到响应。我得到一个 websocket url 以及 JSON 中的其他一些项目。我还没有想出如何在 Flutter 中捕获该响应,但如果我也找到了那篇文章,我会更新它。

从那里开始,我相信我们需要从该新 url 动态创建 websocket 并将我们的订阅 graphql blob 发送到那里。

绝对,这是令人费解的,但这是我现在要走的路。

更新: AWS Amplify for Flutter 现在支持订阅!我正在使用混合解决方案。我有flutter_graphqlartemis用于突变/查询。对于我正在使用的订阅amplify_api: '<1.0.0'。它在过去几周刚刚发布。实际上,我只花了几分钟就让它工作了。Amplify 会自动为您进行 URL 解析和身份验证。

链接到官方文档

您需要生成一个amplifyconfiguration.dart特定于您的 AWS 终端节点并将其添加到您的项目中。AWS 文档涵盖了这一点,设置您的 AWS 终端节点的人应该确切地知道您需要什么。

来自链接的示例:

try {
    String graphQLDocument = '''subscription OnCreateTodo {
        onCreateTodo {
          id
          name
          description
        }
      }''';

    var operation = Amplify.API.subscribe(
        request: GraphQLRequest<String>(document: graphQLDocument),
        onData: (event) {
          print('Subscription event data received: ${event.data}');
        },
        onEstablished: () {
          print('Subscription established');
        },
        onError: (e) {
          print('Subscription failed with error: $e');
        },
        onDone: () {
          print('Subscription has been closed successfully');
        });
} on ApiException catch (e) {
    print('Failed to establish subscription: $e');
}

不要忘记取消订阅:

// Cancel the subscription when you're finished with it
operation.cancel();
于 2021-02-02T15:50:53.313 回答
0

我在这里尝试的第一件事是使用@JLuisRojas 的自定义 AppSync 请求序列化程序:

class AppSyncRequest extends RequestSerializer {
  final Map<String, dynamic> authHeader;

  const AppSyncRequest({
    this.authHeader,
  });

  @override
  Map<String, dynamic> serializeRequest(Request request) => {
    "data": jsonEncode({
      "query": printNode(request.operation.document),
      "variables": request.variables,
    }),
    "extensions": {
      "authorization": this.authHeader,
    }
  };
}

// ...

final token = session.getAccessToken().getJwtToken();

String toBase64(Map data) => base64.encode(utf8.encode(jsonEncode(data)));

final authHeader = {
  "Authorization": token,
  "host": "$apiId.appsync-api.$zone.amazonaws.com",
};

final encodedHeader = toBase64(authHeader);

final WebSocketLink wsLink = WebSocketLink(
  'wss://$apiId.appsync-realtime-api.$zone.amazonaws.com/graphql?header=$encodedHeader&payload=e30=',
  config: SocketClientConfig(
    serializer: AppSyncRequest(authHeader: authHeader),
    inactivityTimeout: Duration(seconds: 60),
  )
);

final AuthLink authLink = AuthLink(
  getToken: () => token,
);

final Link link = authLink.concat(wsLink);

请注意,连接似乎不仅需要header查询参数,而且还需要extensions在每个请求的字段中进行授权,以及非标准的编码结构(文档)。

于 2021-02-10T01:35:36.427 回答