Flutter:如何永久注册传感器(并且永远不会取消注册?)

2023-12-29

TL;DR 如何让 Android 传感器永久运行/活动/注册我的应用程序,即使我关闭它?

客观的:
我正在制作一个 Flutter 应用程序,使用以下方法来计算您的步数计步器 https://pub.dev/packages/pedometer包裹,
它使用内置传感器TYPE_STEP_COUNTER安卓系统的 https://developer.android.com/reference/android/hardware/Sensor#TYPE_STEP_COUNTER,
which 返回自上次启动以来执行的步骤数 (iOS)。在 Android 上,安装应用程序之前执行的任何步骤均不计算在内。 https://pub.dev/packages/pedometer#:%7E:text=The%20step%20count%20represents%20the%20number%20of%20steps%20taken%20since%20the%20last%20system%20boot.%20On%20Android%2C%20any%20steps%20taken%20before%20installing%20the%20application%20will%20not%20be%20counted.

我是如何实现的:

  • 当应用程序在前台主动运行时,每个步骤都会导致 AmyStepCount增加 1。
  • 在所有其他情况下(手机锁定,进入主屏幕,关闭应用程序......), 安卓TYPE_STEP_COUNTER sensor 应该 仍在运行在后台,一旦我再次打开我的应用程序, 新与新的区别stepCount和最后保存的stepCount(已保存 使用shared_prefs)将被计算并添加到myStepCount.

重要的:
The TYPE_STEP_COUNTER传感器必须在后台永久运行/保持注册 https://developer.android.com/reference/android/hardware/Sensor#:%7E:text=If%20you%20want,is%20not%20activated.,即使在我锁定手机、转到主屏幕或关闭应用程序之后...

观察结果:

  • 在我的三星 Galaxy A02s 上,我的应用程序运行得非常好,正如它预期的那样 (如上所述)。那是因为在那部手机上我也有 安装了 Google Fit 应用程序,该应用程序 24/7 跟踪您的步数(因此TYPE_STEP_COUNTER传感器已永久注册)。
  • 在我的 Samsung Galaxy S7 上,我的应用程序不起作用正如它应该的那样。myStepCount当我在应用程序运行时采取步骤时,会增加 在前台运行。但应用程序关闭时采取的步骤 将要NOT被添加到myStepCount一旦我再次打开应用程序。
    注意:我的这款手机上没有任何其他计步应用程序(例如 Google Fit)。

结论:
我需要找到一种方法来注册TYPE_STEP_COUNTER来自我的 Flutter 应用程序的传感器,即使在我关闭应用程序后也保持其注册状态。

2 尝试过(但不成功)的解决方案:

第一次尝试:
从我的 Flutter 代码中调用本机 Android 代码来注册传感器
这是我的main.dart文件(为了简单起见,省略了不重要的部分):

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(App());
}

class App extends StatefulWidget {
  @override
  _AppState createState() => _AppState();
}

class _AppState extends State<App> with WidgetsBindingObserver {

  @override
  void initState() {
    super.initState();

    if (Platform.isAndroid) {
      _activateStepCounterSensor();
    } else if (Platform.isIOS) {
      //TODO check if anything is needed to to here
    }
  }

  void _activateStepCounterSensor() async {
    MethodChannel _stepCounterChannel = MethodChannel('com.cedricds.wanderapp/stepCounter'); //convention
    dynamic result = await _stepCounterChannel.invokeMethod('activateStepCounterSensor');
    switch (result) {
      case "success":
        //The following line gets printed when I run the flutter app on my Samsung Galaxy S7:
        print('_activateStepCounterSensor(): successfully registered step counter sensor for android');
        break;
      case "error":
        print('_activateStepCounterSensor(): failed to register step counter sensor (not available) for android');
        //TODO display errorpage (because app is completely useless in this case)
        break;
      default:
        print('_activateStepCounterSensor(): unknown result: $result');
        break;
    }
  }

  //build() and other lifecycle-methods and helper methods: not important for this question
}

这是我的MainActivity.kt file:

package com.cedricds.wanderapp

import android.content.Context
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.util.Log
import android.widget.Toast
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity2: FlutterActivity(), SensorEventListener {

    private val STEP_COUNTER_CHANNEL = "com.cedricds.wanderapp/stepCounter";
    private lateinit var channel: MethodChannel

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)

        channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, STEP_COUNTER_CHANNEL)
        channel.setMethodCallHandler { call, result ->
            when(call.method){ //this is like switch-case statement in Java
                "activateStepCounterSensor" -> {
                    activateStepCounterSensor(result)
                }
            }
        }
    }

    private var sensorManager : SensorManager?=null
    private var sensor: Sensor ?= null

    private fun activateStepCounterSensor(result: MethodChannel.Result) {
        //This line gets printed when I run the flutter app, so the method gets called successfully:
        Log.d("Android", "Native Android: activateStepCounterSensor()")
        
        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
        sensor = sensorManager?.getDefaultSensor(Sensor.TYPE_STEP_COUNTER)
        if (sensor == null) {
            Toast.makeText(this, "missing hardware.", Toast.LENGTH_LONG).show()
            result.error("error", "error", "error")
        } else {
            sensorManager?.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL)
            //This line gets printed:
            Log.d("Android", "Native Android: registered TYPE_STEP_COUNTER")
            //and never unregister that listener
            result.success("success")
        }
    }

    override fun onSensorChanged(p0: SensorEvent?) {}
    override fun onAccuracyChanged(p0: Sensor?, p1: Int) {}
}

尽管为数不多print(...) and Log.d(...)按预期在控制台中打印,该应用程序无法按我预期的方式工作。当我退出应用程序时,步行例如 50 步,然后再次打开应用程序,这 50 步就消失了。传感器似乎在某处未注册。

第二次尝试:
通过删除修改计步器包的代码unregisterListener(...): 我对文件所做的唯一更改是 2Log.d(...)语句,更重要的是,注释掉特定的代码行。

修改的SensorStreamHandler.kt来自计步器包:

package com.example.pedometer

import android.content.Context
import android.hardware.Sensor
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.os.Looper
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.EventChannel
import android.os.Handler
import android.util.Log

class SensorStreamHandler() : EventChannel.StreamHandler {

    private var sensorEventListener: SensorEventListener? = null
    private var sensorManager: SensorManager? = null
    private var sensor: Sensor? = null
    private lateinit var context: Context
    private lateinit var sensorName: String
    private lateinit var flutterPluginBinding: FlutterPlugin.FlutterPluginBinding

    constructor(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding, sensorType: Int) : this() {
        this.context = flutterPluginBinding.applicationContext
        this.sensorName = if (sensorType == Sensor.TYPE_STEP_COUNTER) "StepCount" else "StepDetection"
        sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
        sensor = sensorManager!!.getDefaultSensor(sensorType)
        this.flutterPluginBinding = flutterPluginBinding
    }

    override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
        Log.d("Pedometer", "Native Android: onListen()")
        if (sensor == null) {
            events!!.error("1", "$sensorName not available",
                    "$sensorName is not available on this device");
        } else {
            sensorEventListener = sensorEventListener(events!!);
            sensorManager!!.registerListener(sensorEventListener, sensor, SensorManager.SENSOR_DELAY_NORMAL);
        }
    }

    override fun onCancel(arguments: Any?) {
        Log.d("Pedometer", "Native Android: onCancel()")
        
        //The only change I did: commenting out the following line:
//        sensorManager!!.unregisterListener(sensorEventListener);
    }

}

这也没有解决我的问题。因此,如果有人知道如何在我的 flutter 应用程序中永久注册 TYPE_STEP_COUNTER 传感器,请告诉我。


更新: 我已经联系了计步器包的开发人员之一,他建议我使用flutter_foreground_service https://pub.dev/packages/flutter_foreground_service(与计步器由同一团队/公司开发)。有用。

但如果有另一种方法(也许类似于我的两次失败的尝试),我仍然会觉得它很有趣。


有很多人要求我更详细地描述我如何解决我的问题。不幸的是,我无法与您分享我的整个代码,只是这个小片段总是在开始时运行(紧接着main()):

    if (Platform.isAndroid && !SharedPrefsHelper().isForegroundServiceStarted()) {
      ForegroundService().start();
      // ForegroundServiceNotification.setPriority(AndroidNotificationPriority.LOW);
      SharedPrefsHelper().setIsForegroundServiceStarted(true);
    }

不用担心 SharedPrefsHelper,这只是我创建的一个类,以便更容易使用共享首选项 https://pub.dev/packages/shared_preferences.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flutter:如何永久注册传感器(并且永远不会取消注册?) 的相关文章

随机推荐