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 11.1.1]Permission issue in Android 14 #1090

Open
KK-dev-mobile opened this issue Dec 3, 2024 · 5 comments
Open

[Health 11.1.1]Permission issue in Android 14 #1090

KK-dev-mobile opened this issue Dec 3, 2024 · 5 comments
Labels
bugfix a bug fix

Comments

@KK-dev-mobile
Copy link

KK-dev-mobile commented Dec 3, 2024

Plugin Name

health

Plugin Version

11.1.1

Device

all android 14 devices

Operating System

Android 14

Describe the bug

My flutter project is targeting android 14 (API 34) but when i install release APK in android 14 it doesn't asks for health data permissions, in health connect I saw "needs updating" for my flutter app. why it is ?

Steps to Reproduce

setup health connect in your peoject, target android 34 API(android 14), make a release APK, install in android 14 devices

Expected Behavior

Should ask for health data permissions in every higher android versions.

Actual Behavior

Not asking for health data permission in android 14 and health connect is showing "needs updating" for my app.

Flutter Logs

No response

Screenshots

No response

Flutter Doctor Output

[✓] Flutter (Channel stable, 3.24.3, on macOS 12.6.3 21G419 darwin-x64, locale en-AU)
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[!] Xcode - develop for iOS and macOS (Xcode 14.2)
    ! Flutter recommends a minimum Xcode version of 15.
      Download the latest version or update via the Mac App Store.
[✓] Chrome - develop for the web
[✓] Android Studio (version 2022.2)
[✓] VS Code (version 1.95.3)
[✓] Connected device (2 available)
[✓] Network resources

! Doctor found issues in 1 category.

Additional Information

Please fix the issue ASAP.

@KK-dev-mobile KK-dev-mobile added the bugfix a bug fix label Dec 3, 2024
@KK-dev-mobile KK-dev-mobile changed the title Permission issue in Android 14 [Health 11.1.0]Permission issue in Android 14 Dec 3, 2024
@KK-dev-mobile KK-dev-mobile changed the title [Health 11.1.0]Permission issue in Android 14 [Health 11.1.1]Permission issue in Android 14 Dec 3, 2024
@iarata
Copy link
Contributor

iarata commented Dec 3, 2024

@KK-dev-mobile Are you running the example app? Also is this on an emulator or actual device?

@KK-dev-mobile
Copy link
Author

KK-dev-mobile commented Dec 3, 2024

@KK-dev-mobile Are you running the example app? Also is this on an emulator or actual device?

No I am not running example app, I've done my own setup using docs reference and I am testing it in both debug and release mode with emulator and real devices.

still the issue is same for android 14 only that the permission is not getting invoked and in health connect in manage permissions section they're showing needs updating for my app and my app is targeting android 14 (API 34) also. Everything is working fine in android 13 and lower.

I am attaching my health controller's code that is using Getx :-


import 'dart:io';
import 'package:corporate_fitness_app/api_setup/api_provider.dart';
import 'package:corporate_fitness_app/services/pref_services.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:health/health.dart';
import 'package:intl/intl.dart';

class HealthDataController extends GetxController {
  RxInt stepsGoal = 0.obs;
  RxInt caloriesGoal = 0.obs;
  RxInt distanceGoal = 0.obs;
  RxInt stepsCount = 0.obs;
  RxDouble caloriesBurned = 0.0.obs;
  RxDouble distanceCovered = 0.0.obs;
  RxDouble heartRate = 0.0.obs;

  // Retrieve user goals from preferences
  Future<void> getGoals() async {
    String dailyStepsGoal = await PrefService.getDailyStepsGoal();
    String dailyCaloriesGoal = await PrefService.getDailyCaloriesGoal();
    String dailyDistanceGoal = await PrefService.getDailyDistanceGoal();

    stepsGoal.value = int.tryParse(dailyStepsGoal) ?? 0;
    caloriesGoal.value = int.tryParse(dailyCaloriesGoal) ?? 0;
    distanceGoal.value = int.tryParse(dailyDistanceGoal) ?? 0;
  }

  // Main function to fetch health data
  Future<void> getHealthData() async {
    final Health health = Health();
    health.configure();

    // Ensure Health Connect is available on Android
    if (Platform.isAndroid) {
      bool isAvailable = await health.isHealthConnectAvailable();
      debugPrint('Health Connect available: $isAvailable');
      if (!isAvailable) {
        try {
          debugPrint('Installing Health Connect...');
          await health.installHealthConnect();
        } catch (e) {
          debugPrint('User canceled Health Connect installation');
          return;
        }
      }
    }

    // Define health data types
    var types = Platform.isAndroid
        ? [
            HealthDataType.STEPS,
            HealthDataType.HEART_RATE,
            HealthDataType.DISTANCE_DELTA,
            HealthDataType.TOTAL_CALORIES_BURNED,
          ]
        : [
            HealthDataType.STEPS,
            HealthDataType.HEART_RATE,
            HealthDataType.DISTANCE_WALKING_RUNNING,
            HealthDataType.BASAL_ENERGY_BURNED,
            HealthDataType.ACTIVE_ENERGY_BURNED,
          ];

    // Check for existing permissions and request if needed
    try {
      bool requested = await health.requestAuthorization(types);
      if (!requested) {
        debugPrint('Authorization not granted');
        return;
      }
    } catch (e) {
      debugPrint('Error requesting authorization: $e');
      return;
    }

    // Fetch and process health data
    await fetchHealthData(health, types);
  }

  // Fetch health data points
  Future<void> fetchHealthData(
      Health health, List<HealthDataType> types) async {
    var now = DateTime.now();
    DateTimeRange range = DateTimeRange(
      start: DateTime(now.year, now.month, now.day),
      end: now,
    );

    try {
      List<HealthDataPoint> healthData = await health.getHealthDataFromTypes(
        types: types,
        startTime: range.start,
        endTime: range.end,
      );
      parseHealthData(healthData, now);
    } catch (e) {
      debugPrint('Error fetching health data: $e');
    }
  }

  // Parse and calculate health data
  void parseHealthData(List<HealthDataPoint> healthData, DateTime now) async {
    int totalSteps = 0;
    double totalCalories = 0;
    double totalDistance = 0;
    double totalHeartRate = 0;
    int heartRateCount = 0;
    debugPrint("Healthdata : ${healthData.toString()}");
    for (var data in healthData) {
      switch (data.type) {
        case HealthDataType.STEPS:
          totalSteps += (data.value as NumericHealthValue).numericValue.toInt();
          break;
        case HealthDataType.TOTAL_CALORIES_BURNED:
        case HealthDataType.BASAL_ENERGY_BURNED:
        case HealthDataType.ACTIVE_ENERGY_BURNED:
          totalCalories += (data.value as NumericHealthValue).numericValue;
          break;
        case HealthDataType.DISTANCE_DELTA:
        case HealthDataType.DISTANCE_WALKING_RUNNING:
          totalDistance += (data.value as NumericHealthValue).numericValue;
          break;
        case HealthDataType.HEART_RATE:
          totalHeartRate += (data.value as NumericHealthValue).numericValue;
          heartRateCount++;
          break;
        default:
          break;
      }
    }

    double avgHeartRate =
        heartRateCount > 0 ? totalHeartRate / heartRateCount : 0;

    stepsCount.value = totalSteps;
    caloriesBurned.value = totalCalories;
    distanceCovered.value = totalDistance / 1000; // Convert to km
    heartRate.value = avgHeartRate;

    // debugPrint('Steps: $totalSteps');
    // debugPrint('Calories: $totalCalories');
    // debugPrint('Distance: ${totalDistance / 1000} km');
    // debugPrint('Avg Heart Rate: $avgHeartRate');

    // Save the data to the server
    await saveDataToServer(now);
  }

  // Save the processed data to the server
  Future<void> saveDataToServer(DateTime now) async {
    var date = DateFormat('yyyy-MM-dd').format(now);
    var res = await ApiProvider.saveUserFitnessData(reqBody: [
      {"value": stepsCount.value.toInt(), "unit": "steps", "date": date},
      {"value": caloriesBurned.value.toInt(), "unit": "calories", "date": date},
      {"value": heartRate.value.toInt(), "unit": "heartrate", "date": date},
      {
        "value": distanceCovered.value.toInt(),
        "unit": "distance",
        "date": date
      },
    ]);
    debugPrint("Saving data response: $res");
  }
}


@tajjacob
Copy link

@KK-dev-mobile can you share:

  1. the error message from I/FLUTTER_HEALTH:
  2. AndroidManifest.xml
  3. MainActivity

I don't see the following functions in your code:
await Permission.activityRecognition.request();

await Permission.location.request();

    // Check if we have health permissions
    bool? hasPermissions =
        await Health().hasPermissions(types, permissions: permissions);

@mithatns
Copy link

mithatns commented Jan 3, 2025

i have error to in android 14 can not show to request permission for activityRecognition. I use the Pedometer plugin
can u show me how to fix in android 14 because i read that permission for foreground service

@MedLighter
Copy link

MedLighter commented Jan 28, 2025

@KK-dev-mobile Did you find out what the problem was? I faced the same situation.

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