How can I integrate Google FIT in Flutter app? - flutter

I want steps count and calories burned data in my flutter app. I am using health: ^3.1.1+1 package but I'm getting "Authorization not granted" even after giving all permission. I even used permission handler for permission and I was successfully getting permission with permission handler, still I am not getting data from health package. Please help me with the process to authorize my app to fetch data from Google Fit API.
I have successfully generate my OAuth client id from google console and added the json file in my project. Please let me know if there is any other place where I need to add my client id.
I am using given below sample code provided in with the package.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:health/health.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
enum AppState {
DATA_NOT_FETCHED,
FETCHING_DATA,
DATA_READY,
NO_DATA,
AUTH_NOT_GRANTED
}
class _MyAppState extends State<MyApp> {
List<HealthDataPoint> _healthDataList = [];
AppState _state = AppState.DATA_NOT_FETCHED;
#override
void initState() {
super.initState();
}
/// Fetch data from the healt plugin and print it
Future fetchData() async {
// get everything from midnight until now
DateTime startDate = DateTime(2020, 11, 07, 0, 0, 0);
DateTime endDate = DateTime(2025, 11, 07, 23, 59, 59);
HealthFactory health = HealthFactory();
// define the types to get
List<HealthDataType> types = [
HealthDataType.STEPS,
HealthDataType.WEIGHT,
HealthDataType.HEIGHT,
HealthDataType.BLOOD_GLUCOSE,
HealthDataType.DISTANCE_WALKING_RUNNING,
];
setState(() => _state = AppState.FETCHING_DATA);
// you MUST request access to the data types before reading them
bool accessWasGranted = await health.requestAuthorization(types);
int steps = 0;
if (accessWasGranted) {
try {
// fetch new data
List<HealthDataPoint> healthData =
await health.getHealthDataFromTypes(startDate, endDate, types);
// save all the new data points
_healthDataList.addAll(healthData);
} catch (e) {
print("Caught exception in getHealthDataFromTypes: $e");
}
// filter out duplicates
_healthDataList = HealthFactory.removeDuplicates(_healthDataList);
// print the results
_healthDataList.forEach((x) {
print("Data point: $x");
steps += x.value.round();
});
print("Steps: $steps");
// update the UI to display the results
setState(() {
_state =
_healthDataList.isEmpty ? AppState.NO_DATA : AppState.DATA_READY;
});
} else {
print("Authorization not granted");
setState(() => _state = AppState.DATA_NOT_FETCHED);
}
}
Widget _contentFetchingData() {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
padding: EdgeInsets.all(20),
child: CircularProgressIndicator(
strokeWidth: 10,
)),
Text('Fetching data...')
],
);
}
Widget _contentDataReady() {
return ListView.builder(
itemCount: _healthDataList.length,
itemBuilder: (_, index) {
HealthDataPoint p = _healthDataList[index];
return ListTile(
title: Text("${p.typeString}: ${p.value}"),
trailing: Text('${p.unitString}'),
subtitle: Text('${p.dateFrom} - ${p.dateTo}'),
);
});
}
Widget _contentNoData() {
return Text('No Data to show');
}
Widget _contentNotFetched() {
return Text('Press the download button to fetch data');
}
Widget _authorizationNotGranted() {
return Text('''Authorization not given.
For Android please check your OAUTH2 client ID is correct in Google Developer Console.
For iOS check your permissions in Apple Health.''');
}
Widget _content() {
if (_state == AppState.DATA_READY)
return _contentDataReady();
else if (_state == AppState.NO_DATA)
return _contentNoData();
else if (_state == AppState.FETCHING_DATA)
return _contentFetchingData();
else if (_state == AppState.AUTH_NOT_GRANTED)
return _authorizationNotGranted();
return _contentNotFetched();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.file_download),
onPressed: () {
fetchData();
},
)
],
),
body: Center(
child: _content(),
)),
);
}
}

Go to Google Cloud Platform > Apis & Services > OAuth consent screen and check if your app is in Testing mode and add gmails to allow user to use the Oauth
Remember to upload the android debug key sha1!

New version of the health package solved my problem.

Related

Futurebuilder is not updating data from firestore

So i am having issue with futurebuilder i want my app to update when a bool is set true but it wasn't working at all so i added a line to to see if the value of bool is changing or not and released it's not changing.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:databse_web_test/database_services/getsocials.dart';
import 'package:flutter/material.dart';
import 'database_services/request.dart';
class RequestWidget extends StatefulWidget {
RequestWidget({Key? key}) : super(key: key);
#override
State<RequestWidget> createState() => _RequestWidgetState();
}
class _RequestWidgetState extends State<RequestWidget> {
String Doc = "EobkN9fONF4IxmpErB1n";
CollectionReference request = FirebaseFirestore.instance
.collection('socails')
.doc("daaJgE8Pz5UQIlNh47UsmwWcqNi1")
.collection("requests");
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: request.doc("EobkN9fONF4IxmpErB1n").get(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return const Text("Something went wrong");
}
if (snapshot.hasData && !snapshot.data!.exists) {
return const Text("Document does not exist");
}
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data =
snapshot.data!.data() as Map<String, dynamic>;
bool isRequested = data["isRequested"];
bool isApproved = data["isApproved"];
if (data["isRequested"] == true && data['isApproved'] == true) {
return GetSocialData();
}
// if (data['isApproved'] == false && data['isRequested'] == true) {
// return Column(
// children: [
// data['isApproved'] == false
// ? const CircularProgressIndicator()
// : GetSocialData()
// ],
// );
// }
if (data['isApproved'] == false && data["isRequested"] == false) {
return Center(
child: ElevatedButton(
onPressed: () {
SendRequest().updateUserData(
isApproved: false, isRequested: true);
setState(() {});
},
child: const Text("data send")));
} else {
return Column(children: [
CircularProgressIndicator(),
Text(snapshot.data!.data().toString())
]);
}
} else {
return const Text("Loading database");
}
});
// if (isRequested == true && isApproved == false) {
// return Center(
// child: ElevatedButton(
// onPressed: () {
// SendRequest()
// .updateUserData(isApproved: false, isRequested: true);
// },
// child: const Text("data send")));
// } else {
// return GetSocialData();
// }
}
}
i really don't know whats wrong since im new to flutter i dont know that much. if i were to use text widget to know if the value is changing i get to know that value isn't changing. this web app is connect to another android app and value of that bool is gonna be updated by that app
A flutter builder it is a one time read, because, if you want to use a realtime read, use a streambuilder, check that in documentation : Flutter Cloud Firestore.
FutureBuilder is used for one time response, like taking an image from Camera, getting data once from native platform (like fetching device battery), getting file reference, making an http request etc.
On the other hand, StreamBuilder is used for fetching some data more than once, like listening for location update, playing a music, stopwatch, etc.
In your case you should use StreamBuilder

Can I receive a share intent without opening my Flutter app?

I'm creating an app in Flutter to store any type of media, imagem, video, pdfs, etc. And I want to be able to receive share intents from other apps in the easiest way possible for the user.
So, my idea is to be able to simply receive the media without needing to open the app for the user to input something, they should simply select my app to receive the media and continue using the "source" app. Is that possible in flutter?
this should work very well based on your requirement, receive_sharing_intent, just following the setup for android & ios and try the example:
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
StreamSubscription _intentDataStreamSubscription;
List<SharedMediaFile> _sharedFiles;
String _sharedText;
#override
void initState() {
super.initState();
// For sharing images coming from outside the app while the app is in the memory
_intentDataStreamSubscription =
ReceiveSharingIntent.getMediaStream().listen((List<SharedMediaFile> value) {
setState(() {
print("Shared:" + (_sharedFiles?.map((f)=> f.path)?.join(",") ?? ""));
_sharedFiles = value;
});
}, onError: (err) {
print("getIntentDataStream error: $err");
});
// For sharing images coming from outside the app while the app is closed
ReceiveSharingIntent.getInitialMedia().then((List<SharedMediaFile> value) {
setState(() {
_sharedFiles = value;
});
});
// For sharing or opening urls/text coming from outside the app while the app is in the memory
_intentDataStreamSubscription =
ReceiveSharingIntent.getTextStream().listen((String value) {
setState(() {
_sharedText = value;
});
}, onError: (err) {
print("getLinkStream error: $err");
});
// For sharing or opening urls/text coming from outside the app while the app is closed
ReceiveSharingIntent.getInitialText().then((String value) {
setState(() {
_sharedText = value;
});
});
}
#override
void dispose() {
_intentDataStreamSubscription.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
const textStyleBold = const TextStyle(fontWeight: FontWeight.bold);
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Column(
children: <Widget>[
Text("Shared files:", style: textStyleBold),
Text(_sharedFiles?.map((f)=> f.path)?.join(",") ?? ""),
SizedBox(height: 100),
Text("Shared urls/text:", style: textStyleBold),
Text(_sharedText ?? "")
],
),
),
),
);
}
}
Using Receive Sharing intent package, you can receive text & media files in closed as well as opened application.
Below code snippet to receive intent in closed application,
// For sharing images coming from outside the app while the app is closed
ReceiveSharingIntent.getInitialMedia().then((List<SharedMediaFile> value) {
setState(() {
_sharedFiles = value;
});
});
You can go through this link for further understanding on how to receive intent in already opened & closed application.

I'm using the Paytm all in one sdk in my flutter application. It's throwing PlatformException error

In my app, in a page I'm calling the startTransaction() plugin method, and storing the response as in the paytm documentation. On recieving response, I want to return the the status whether it was success or failure to previous page. So in init() function I'm calling another async method to startTransaction and check for the response.
PlatformException (0, Unknown error, {response : { response of transaction})
class StartTransaction extends StatefulWidget {
int orderId;
double totalAmount;
PaymentPayload paymentPayload;
bool success;
StartTransaction({this.orderId,this.totalAmount});
#override
_StartTransactionState createState() => _StartTransactionState();
}
class _StartTransactionState extends State<StartTransaction> {
#override
void initState() {
super.initState();
initiateTransaction();
}
Future initiateTransaction() async {
if(widget.success == null){
widget.paymentPayload = await createPaymentGateway(
widget.orderId,
userBloc.userData.username,
widget.totalAmount.toStringAsFixed(2),
context);
var pgResp = AllInOneSdk.startTransaction(
widget.paymentPayload.mid,
widget.orderId.toString(),
widget.totalAmount.toStringAsFixed(2),
widget.paymentPayload.txnToken,
widget.paymentPayload.callbackUrl,
true,
false);
pgResp.then((value) {
print(value);
setState(() {
widget.success = value['RESPCODE'] == 01;
});
}).catchError((onError) {
setState(() {
widget.success = false;
});
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: FutureBuilder(
builder: (context, snapshot) {
if(widget.success == true) {
print('Payment successful');
Navigator.pop(context,true);
} else if(widget.success == false) {
print('Payment unsuccessful');
Navigator.pop(context,false);
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text('We are processing your transaction', style: TextStyle(fontSize: 36),),
CircularProgressIndicator(),
],
),
);
}
),
),
);
}
}```
You need to call transaction status API based on the order id and MID used in the transaction. There is no need to call the starttransaction method again
You should validate the transaction response via a server-side request using the Transaction Status API. This API requires checksumhash in request and response. You must verify the Order ID and Amount with your data. The status should be treated as the final status of the transaction in all cases.
You need to use our static callback url in this case
Staging Environment: "https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=<order_id>"
Production Environment: "https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=<order_id>"

how to get mobile number in flutter

I am using "mobile_number(version - 1.0.3)" plugin to get mobile number in flutter app, am running in original device but i couldn't get mobile number.instead of errors i can get mobile number as null along with other sim details as shown in screen shot.
help me to resolve this problem, i had just copy pasted the example given by plugin that is the code
plugin link
It says:
Note: If the mobile number is not pre-exist on sim card it will not return te phone number.
I think mobile number does not pre-exist on the SIM if the SIM is not original (i.e. replaced)
If the phone number isn't stored on the sim (aka null), then you can't get it from anywhere else, in that case you probably want to forward the user to a different page where they can type the phone number using TextField and then store it somewhere
Use Mobile_number package to get mobile number and other details. For example
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:mobile_number/mobile_number.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _mobileNumber = '';
List<SimCard> _simCard = <SimCard>[];
#override
void initState() {
super.initState();
MobileNumber.listenPhonePermission((isPermissionGranted) {
if (isPermissionGranted) {
initMobileNumberState();
} else {}
});
initMobileNumberState();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initMobileNumberState() async {
if (!await MobileNumber.hasPhonePermission) {
await MobileNumber.requestPhonePermission;
return;
}
String mobileNumber = '';
// Platform messages may fail, so we use a try/catch PlatformException.
try {
mobileNumber = (await MobileNumber.mobileNumber)!;
_simCard = (await MobileNumber.getSimCards)!;
} on PlatformException catch (e) {
debugPrint("Failed to get mobile number because of '${e.message}'");
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_mobileNumber = mobileNumber;
});
}
Widget fillCards() {
List<Widget> widgets = _simCard
.map((SimCard sim) => Text(
'Sim Card Number: (${sim.countryPhonePrefix}) - ${sim.number}\nCarrier Name: ${sim.carrierName}\nCountry Iso: ${sim.countryIso}\nDisplay Name: ${sim.displayName}\nSim Slot Index: ${sim.slotIndex}\n\n'))
.toList();
return Column(children: widgets);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Column(
children: <Widget>[
Text('Running on: $_mobileNumber\n'),
fillCards()
],
),
),
),
);
}
}

Flutter switch between local data and remote data

In a Flutter app the user must be able to see the retrieved data from an API also when there is no network, e.g. in a house basement. I'm able to retrieve the data from the Api and to store it in a local sqflite db. I'm also able to check whether there is network or not. But how do I implement the flow in order to show local data or remote data? Is it possible to do it in the same screen or do I need two screens? Any help is appreciated.
EDIT
Thank you for all the answers, but I don't check where to fill in the getData() method now. I post what I've done so far:
class WorkAtPop extends StatefulWidget {
#override
_WorkAtPop createState() => _WorkAtPop();
}
class _WorkAtPop extends State<WorkAtPop> {
final String title = 'Work#Pop';
final bgcolor = HexToColor('#ffffff');
final list = List();
final isLoading = false;
List<DropdownChoices> workatpopdropdownchoices = <DropdownChoices>[
DropdownChoices(title: 'Refresh', action: 'refresh', route: '/workatpop'),
];
bool _isVpnEnabled = false;
bool _isLoading = true;
void checkVpn() async {
var isEnabled = await ApiService().isVpnEnabled();
setState(() => _isVpnEnabled = isEnabled);
setState(() => _isLoading = false);
}
#override
void initState() {
super.initState();
checkVpn();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: BaseAppBar(title: title, appBar: AppBar(), dropdownChoices: workatpopdropdownchoices),
backgroundColor: bgcolor,
body: new Container(
padding: const EdgeInsets.all(30.0),
color: bgcolor,
child: (_isLoading)
? new Center(
child: new CircularProgressIndicator(),
)
: new Container(
child: new Text('here my data displayed as list, vpn=$_isVpnEnabled'),
)
),
);
}
}
Now if VPN is enabled I retrieve the data from the api else from the local db. The API is storing the data into the db each time it is called.
Since you're handling everything, it will be easy for you to do so. It's possible only in a single screen.
List<PodoClass> data;
if(internet()) {
data = fecthDataFromNetwork(); // load fron internet
} else {
data = loadLocalData(); // load from database
}
processData(data); // process your data
I hope you got some idea.
If internet is available get data from server and store it in localdb, and if internet is not available get already stored data from localdb.
List<PodoClass> data;
void feachdata() async{
if(isInternet()) {
data = await DataFromNetwork(); // load from internet
storetolocaldb(data); // store to local for later use
} else {
data = getLocalData(); // load from database
}
displaydata(data); // process your data
}
hope it helps..
you can store retrieved data from an API to a local db and can fetch it on both cases offline/online.. Also you can update the db if any new data available in the api
void getData() {
getStoredDataFromDb().then((data){
if(data !=null){
populateUI();
checkForAnyUpdate();
}
else {
if(hasInternetconnection)
getDatafromApi();
}
else{
loadMockOrOldData();}
};
getDatafromApi().then((response){
insertDataIntoTheDatabase(response);
};
}