I'm new to flutter and graphql I'm trying to develop an app to consume backend api hosted on heroku during development and while testing the app on my Samsung Note 5, the app connects successfully to the backend and I can fetch data from query and mutation but after building the app-release.apk and installing it on the same mobile, the response is always null in both the query and mutation. Also, I have REST api within the backend and I use Dio lib to send requests but I don't get any response from these requests. I tried "flutter clean" but in vain flutter doctor command shows no error:
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!
I'm using 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