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 中不起作用