flutter_graphql 不起作用,并且在应用程序构建后总是返回 null

Posted

技术标签:

【中文标题】flutter_graphql 不起作用,并且在应用程序构建后总是返回 null【英文标题】:flutter_graphql doesn't work and always return null after app build 【发布时间】:2021-09-22 19:41:13 【问题描述】:

我是 Flutter 和 graphql 的新手 我正在尝试开发一个应用程序来使用托管在 heroku 上的后端 api 在开发期间和在我的三星 Note 5 上测试应用程序时,应用程序成功连接到后端,我可以从查询和变异中获取数据 但是在构建 app-release.apk 并将其安装在同一台手机上之后,查询和变异中的响应始终为空。 另外,我在后端有 REST api,我使用 Dio lib 发送请求,但我没有从这些请求中得到任何响应。 我试过“扑干净”但徒劳无功 flutter doctor 命令显示没有错误:

Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 2.0.3, on Microsoft Windows [Version 10.0.18363.1646], locale en-US)
[√] android toolchain - develop for Android devices (Android SDK version 30.0.3)
[√] Chrome - develop for the web
[√] Android Studio
[√] VS Code (version 1.54.3)
[√] Connected device (2 available)

• No issues found!

我正在使用 android studio 4.2.2

main.dart

bool isAuth;

void main() async 
  WidgetsFlutterBinding.ensureInitialized();
  await initHiveForFlutter();
  isAuth = await isAuthenticated();
  runApp(MyApp());


class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return GraphQLProvider(
      client: client,
      child: MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'Flutter App',
          theme: ThemeData(
            primarySwatch: Colors.red,
          ),
          initialRoute: isAuth ? 'HomeScreen' : 'LoginScreen',
          routes: 
            'HomeScreen': (context) => HomeScreen(),
            'LoginScreen': (context) => LoginScreen()
          ),
    );
  

authentication.dart

// check if token is set using sharedPreferences lib
Future<bool> isAuthenticated() async 
  final accessToken = await getAccessToken(); 
  if (accessToken != null) 
    return true;
  
  return false;

GraphQLConfiguration.dart:

class GraphQLConfiguration 

  HttpLink _httpLink;
  AuthLink _authLink;
  Link _link;

  GraphQLConfiguration () 
    _httpLink = new HttpLink('https://backendapi.herokuapp.com/graphql');
    _authLink = new AuthLink(getToken: () async => 'Bearer $await getAccessToken()');
    _link = _authLink.concat(_httpLink);
  

  GraphQLClient myGQLClient() 
    return GraphQLClient(
      link: _link,
      cache: GraphQLCache(store: HiveStore()),
    );
  

ValueNotifier<GraphQLClient> client = ValueNotifier(GraphQLConfiguration().myGQLClient());

mutations.dart

String login() 
    return '''
      mutation login(\$data: LoginInput!)
        login(data: \$data)
          status
          message
          accessToken
         
      
    ''';
  

LoginScreen.dart


class LoginScreen extends StatefulWidget 
  @override
  _LoginScreenState createState() => _LoginScreenState();


class _LoginScreenState extends State<LoginScreen> 
  bool _hidePassword = true;

  final TextEditingController _usernameController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      resizeToAvoidBottomInset: false,
      body: Stack(
        children: [
          Mutation(
            options: MutationOptions(
                document: gql(mutations.login()),
                update: (GraphQLDataProxy cache, QueryResult result) 
                  String cookie;
                  final String cookieHeader = result.context
                      .entry<HttpLinkResponseContext>()
                      .headers['set-cookie'];
                  if (cookieHeader != null) 
                    cookie = cookieHeader.split(';')[0];
                  

                  final LoginResponse loginResponse =
                      LoginResponse.from(result.data['login']);

                  if (loginResponse.status == true && cookie != null) 
                    setRefreshToken(cookie);
                  
                  return cache;
                ,
                onCompleted: (resultData) async 
                  final LoginResponse loginResponse =
                      LoginResponse.from(resultData['login']);
                  if (loginResponse.status == true) 
                    await setAccessToken(loginResponse.accessToken);
                    Navigator.pushReplacement(context,
                        MaterialPageRoute(builder: (context) => HomeScreen()));
                  
                  Fluttertoast.showToast(
                    msg: loginResponse.message,
                    backgroundColor: Colors.grey,
                    gravity: ToastGravity.BOTTOM,
                    fontSize: 16.0,
                    timeInSecForiosWeb: 1,
                    textColor: Colors.white,
                    toastLength: Toast.LENGTH_LONG,
                  );
                ),
            builder: (RunMutation runMutation, QueryResult result) 
              return Column(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: [
                  Container(
                    margin: EdgeInsets.only(top: 100),
                    child: Column(
                      children: [
                        Text(
                          'Welcome...',
                          style: TextStyle(
                            shadows: [
                              Shadow(
                                offset: Offset(0.5, 0.5),
                                blurRadius: 10.0,
                                color: Colors.grey,
                              ),
                            ],
                            fontSize: 45,
                            letterSpacing: 2,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                        Text(
                          'welcome,,,',
                          style: TextStyle(
                            fontSize: 20,
                            letterSpacing: 7,
                          ),
                        )
                      ],
                    ),
                  ),
                  Container(
                    child: Column(
                      children: [
                        Padding(
                          padding:
                              EdgeInsets.symmetric(vertical: 0, horizontal: 20),
                          child: TextField(
                            controller: _usernameController,
                            style: TextStyle(
                              fontSize: 22.0,
                            ),
                            decoration: InputDecoration(
                              labelText: 'Username',
                              border: OutlineInputBorder(
                                borderRadius: BorderRadius.circular(50.5),
                              ),
                              prefixIcon:
                                  Icon(Icons.supervised_user_circle_outlined),
                            ),
                          ),
                        ),
                        Padding(
                          padding: EdgeInsets.symmetric(
                              vertical: 10, horizontal: 20),
                          child: TextField(
                            controller: _passwordController,
                            obscureText: _hidePassword,
                            style: TextStyle(
                              fontSize: 22.0,
                            ),
                            decoration: InputDecoration(
                              labelText: 'Password',
                              border: OutlineInputBorder(
                                borderRadius: BorderRadius.circular(50.5),
                              ),
                              prefixIcon: Icon(Icons.lock),
                              suffixIcon: IconButton(
                                icon: Icon(_hidePassword
                                    ? Icons.visibility
                                    : Icons.visibility_off),
                                onPressed: () => _togglePasswordVisibility(),
                              ),
                            ),
                          ),
                        ),
                        Padding(
                          padding: EdgeInsets.only(top: 30),
                          child: ElevatedButton(
                            style: ButtonStyle(
                              padding: MaterialStateProperty.all<EdgeInsets>(
                                  EdgeInsets.all(15)),
                              minimumSize:
                                  MaterialStateProperty.all<Size>(Size(370, 0)),
                              shape: MaterialStateProperty.all<
                                  RoundedRectangleBorder>(
                                RoundedRectangleBorder(
                                  borderRadius: BorderRadius.circular(50.0),
                                  side: BorderSide(color: Colors.red),
                                ),
                              ),
                              backgroundColor:
                                  MaterialStateProperty.all<Color>(Colors.red),
                            ),
                            onPressed: () => runMutation(
                              
                                'data': 
                                  'username': _usernameController.text,
                                  'password': _passwordController.text
                                
                              ,
                            ),
                            child: Text(
                              'Login',
                              style: TextStyle(
                                fontSize: 30.0,
                              ),
                            ),
                          ),
                        ),
                      ],
                    ),
                  ),
                  Container(
                    margin: EdgeInsets.only(top: 100),
                    padding: EdgeInsets.only(bottom: 20),
                    child: Center(
                      child: Text(
                        'BY XXX',
                        style: TextStyle(
                          color: Colors.grey,
                          fontWeight: FontWeight.bold,
                          fontSize: 10,
                        ),
                      ),
                    ),
                  ),
                ],
              );
            ,
          ),
        ],
      ),
    );
  

  void _togglePasswordVisibility() 
    setState(() 
      _hidePassword = !_hidePassword;
    );
  

pubspec.yaml


environment:
  sdk: ">=2.7.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  graphql_flutter: ^5.0.0
  shared_preferences: ^2.0.6
  http: ^0.13.3
  fluttertoast: ^8.0.7
  font_awesome_flutter: ^9.1.0
  dio: ^4.0.0
  flutter_datetime_picker: ^1.5.1
  loading_overlay: ^0.3.0

  cupertino_icons: ^1.0.2


dev_dependencies:
  flutter_test:
    sdk: flutter

flutter:

  uses-material-design: true


  assets:
     - assets/images/male.png
     - assets/images/female.png

  fonts:
    - family: Changa
      fonts:
        - asset: fonts/Changa-Regular.ttf
        - asset: fonts/Changa-Bold.ttf
          weight: 700

【问题讨论】:

【参考方案1】:

正如我所说,我是 Flutter 和移动应用开发的新手 并从这个thread获得解决方案

问题与flutter_graphql lib无关,而是与android项目的清单文件有关。 应声明互联网许可。 我以为 Flutter 会根据使用的库自动检测和配置应用权限,但我错了。

【讨论】:

以上是关于flutter_graphql 不起作用,并且在应用程序构建后总是返回 null的主要内容,如果未能解决你的问题,请参考以下文章

应用内购买在准备出售的应用中不起作用?

Xml 音频列表播放器在移动设备上不起作用,并且自动播放不起作用

PickerView 被禁用并且在 SwiftUI 中不起作用

为啥 OleDbCommand 和 OleDbType.Date 不起作用,并且没有错误?

节点。并且 npm start 不起作用

片段不起作用并且有错误