Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[health 2.0.2] Google Play API Sign in failure #172

Closed
Matthew-Pitzer opened this issue Aug 17, 2020 · 8 comments
Closed

[health 2.0.2] Google Play API Sign in failure #172

Matthew-Pitzer opened this issue Aug 17, 2020 · 8 comments
Labels
bugfix a bug fix

Comments

@Matthew-Pitzer
Copy link
Contributor

Device / Emulator and OS

  • Device: Kyocera E6910
  • OS: Android 9

Describe the bug

Whenever I call HealthFactory().getHealthDataFromTypes() with any date range and type I get the prompt to choose an account and get a log message saying access was granted. However after the popup disappears the screen flashes, the app crashes, and I get the following error: com.google.android.gms.common.api.ApiException: 4: The user must be signed in to make this API call.

To Reproduce

  • Create HealthFactory instance
  • Call getHealthDataFromTypes()
  • Grant app permission to use Google Fit

Expected behavior

Ability to read from Google Fit

Actual behavior

E/AndroidRuntime(14110): 	at com.google.android.gms.common.api.internal.GoogleApiManager$zaa.zac(com.google.android.gms:play-services-base@@17.1.0:175)
E/AndroidRuntime(14110): 	at com.google.android.gms.common.api.internal.GoogleApiManager$zaa.onConnectionFailed(com.google.android.gms:play-services-base@@17.1.0:79)
E/AndroidRuntime(14110): 	at com.google.android.gms.common.api.internal.GoogleApiManager$zaa.zag(com.google.android.gms:play-services-base@@17.1.0:60)
E/AndroidRuntime(14110): 	at com.google.android.gms.common.api.internal.GoogleApiManager$zab.zag(com.google.android.gms:play-services-base@@17.1.0:10)
E/AndroidRuntime(14110): 	at com.google.android.gms.common.api.internal.zace.zac(com.google.android.gms:play-services-base@@17.1.0:45)
E/AndroidRuntime(14110): 	at com.google.android.gms.common.api.internal.zace.zaa(com.google.android.gms:play-services-base@@17.1.0:49)
E/AndroidRuntime(14110): 	at com.google.android.gms.common.api.internal.zacg.run(com.google.android.gms:play-services-base@@17.1.0:2)
E/AndroidRuntime(14110): 	at android.os.Handler.handleCallback(Handler.java:873)
E/AndroidRuntime(14110): 	at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime(14110): 	at com.google.android.gms.internal.base.zar.dispatchMessage(com.google.android.gms:play-services-base@@17.1.0:8)
E/AndroidRuntime(14110): 	at android.os.Looper.loop(Looper.java:193)
E/AndroidRuntime(14110): 	at android.os.HandlerThread.run(HandlerThread.java:65)
I/Process (14110): Sending signal. PID: 14110 SIG: 9

Flutter doctor

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 1.20.0, on Mac OS X 10.15.6 19G2021, locale en-US)
 
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
[✓] Xcode - develop for iOS and macOS (Xcode 11.6)
[✓] Android Studio (version 3.6)
[✓] VS Code (version 1.48.0)
[✓] Connected device (2 available)

• No issues found!

Additional information

I am able to use the FitKit plugin perfectly fine, so I know my permissions/OAuth credentials are setup properly.

@Matthew-Pitzer Matthew-Pitzer added the bugfix a bug fix label Aug 17, 2020
@mr-mamali
Copy link

i have this issue too ! also there is not a try catch block for google signIn in the native code , if some error or exception occure it will crash the app

@mr-mamali
Copy link

mr-mamali commented Aug 18, 2020

@Matthew-Pitzer I solved this issue by changing native codes ,
(the methods below are inside android folder and native Kotlin code in package src)
I changed this method(requestAuthorization) to:

    /// Called when the "requestAuthorization" is invoked from Flutter 
    private fun requestAuthorization(call: MethodCall, result: Result) {
//        val optionsToRegister = callToHealthTypes(call)

        mResult = result

        try{
            /// Not granted? Ask for permission
            if (!GoogleSignIn.hasPermissions(GoogleSignIn.getLastSignedInAccount(activity), fitnessOptions)) {
                GoogleSignIn.requestPermissions(
                        activity,
                        GOOGLE_FIT_PERMISSIONS_REQUEST_CODE,
                        GoogleSignIn.getLastSignedInAccount(activity),
                        fitnessOptions)
            }
            /// Permission already granted
            else {
                mResult?.success(true)
            }
        } catch (e3: Exception) {
            Log.e("Exception in auth from google: ", e3.toString())
            mResult?.error("exception","error in auth from google",e3)
        }

    }

and this method (getData) to :

 /// Called when the "getHealthDataByType" is invoked from Flutter
    private fun getData(call: MethodCall, result: Result) {
        val type = call.argument<String>("dataTypeKey")!!
        val startTime = call.argument<Long>("startDate")!!
        val endTime = call.argument<Long>("endDate")!!

        // Look up data type and unit for the type key
        val dataType = keyToHealthDataType(type)
        val unit = getUnit(type)

        println(type)

        /// Start a new thread for doing a GoogleFit data lookup
        thread {
            try{

                val googleSignInAccount = GoogleSignIn.getAccountForExtension(activity.applicationContext, fitnessOptions)

            val response = Fitness.getHistoryClient(activity.applicationContext, googleSignInAccount)
                    .readData(DataReadRequest.Builder()
                            .read(dataType)
                            .setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
                            .build())

            /// Fetch all data points for the specified DataType
            val dataPoints = Tasks.await<DataReadResponse>(response).getDataSet(dataType)

            /// For each data point, extract the contents and send them to Flutter, along with date and unit.
            val healthData = dataPoints.dataPoints.mapIndexed { _, dataPoint ->
                return@mapIndexed hashMapOf(
                        "value" to getHealthDataValue(dataPoint, unit),
                        "date_from" to dataPoint.getStartTime(TimeUnit.MILLISECONDS),
                        "date_to" to dataPoint.getEndTime(TimeUnit.MILLISECONDS),
                        "unit" to unit.toString()
                )

            }
            activity.runOnUiThread { result.success(healthData) }
        } catch (e3: Exception) {
                Log.e("Exception in gettin data from google: ", e3.toString())
                activity.runOnUiThread { result.success(null) }
            }
        }

    }

@Matthew-Pitzer
Copy link
Contributor Author

@mr-mamali Thanks so much for the fix! You're a lifesaver!

@thomasnilsson
Copy link
Contributor

@Matthew-Pitzer I solved this issue by changing native codes ,
(the methods below are inside android folder and native Kotlin code in package src)
I changed this method(requestAuthorization) to:

    /// Called when the "requestAuthorization" is invoked from Flutter 
    private fun requestAuthorization(call: MethodCall, result: Result) {
//        val optionsToRegister = callToHealthTypes(call)

        mResult = result

        try{
            /// Not granted? Ask for permission
            if (!GoogleSignIn.hasPermissions(GoogleSignIn.getLastSignedInAccount(activity), fitnessOptions)) {
                GoogleSignIn.requestPermissions(
                        activity,
                        GOOGLE_FIT_PERMISSIONS_REQUEST_CODE,
                        GoogleSignIn.getLastSignedInAccount(activity),
                        fitnessOptions)
            }
            /// Permission already granted
            else {
                mResult?.success(true)
            }
        } catch (e3: Exception) {
            Log.e("Exception in auth from google: ", e3.toString())
            mResult?.error("exception","error in auth from google",e3)
        }

    }

and this method (getData) to :

 /// Called when the "getHealthDataByType" is invoked from Flutter
    private fun getData(call: MethodCall, result: Result) {
        val type = call.argument<String>("dataTypeKey")!!
        val startTime = call.argument<Long>("startDate")!!
        val endTime = call.argument<Long>("endDate")!!

        // Look up data type and unit for the type key
        val dataType = keyToHealthDataType(type)
        val unit = getUnit(type)

        println(type)

        /// Start a new thread for doing a GoogleFit data lookup
        thread {
            try{

                val googleSignInAccount = GoogleSignIn.getAccountForExtension(activity.applicationContext, fitnessOptions)

            val response = Fitness.getHistoryClient(activity.applicationContext, googleSignInAccount)
                    .readData(DataReadRequest.Builder()
                            .read(dataType)
                            .setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
                            .build())

            /// Fetch all data points for the specified DataType
            val dataPoints = Tasks.await<DataReadResponse>(response).getDataSet(dataType)

            /// For each data point, extract the contents and send them to Flutter, along with date and unit.
            val healthData = dataPoints.dataPoints.mapIndexed { _, dataPoint ->
                return@mapIndexed hashMapOf(
                        "value" to getHealthDataValue(dataPoint, unit),
                        "date_from" to dataPoint.getStartTime(TimeUnit.MILLISECONDS),
                        "date_to" to dataPoint.getEndTime(TimeUnit.MILLISECONDS),
                        "unit" to unit.toString()
                )

            }
            activity.runOnUiThread { result.success(healthData) }
        } catch (e3: Exception) {
                Log.e("Exception in gettin data from google: ", e3.toString())
                activity.runOnUiThread { result.success(null) }
            }
        }

    }

Thanks, I am going to merge this into the plugin 👍

@thomasnilsson
Copy link
Contributor

This will take a little longer since I am without an Android phone for a few more days.

@Mallikarjun7657
Copy link

Mallikarjun7657 commented Sep 5, 2020

i have this issue too ! also there is not a try catch block for google signIn in the native code , if some error or exception occure it will crash the app

I got the same issues too, and i have resolved by modifying the plugin code. Thanks you for your solution

@mr-mamali Thanks so much for the fix! You're a lifesaver!

@mr-mamali Thank you for the fix! You have saved my time to dig in to the issue.

thomasnilsson pushed a commit that referenced this issue Sep 27, 2020
thomasnilsson pushed a commit that referenced this issue Sep 27, 2020
@thomasnilsson
Copy link
Contributor

Fixed in version 2.0.6

@seriousManual
Copy link

thanks, that helped !

hibitness-quan-nguyen2 pushed a commit to hibitness/flutter-plugins that referenced this issue Dec 18, 2023
hibitness-quan-nguyen2 pushed a commit to hibitness/flutter-plugins that referenced this issue Dec 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugfix a bug fix
Projects
None yet
Development

No branches or pull requests

5 participants