تجربه سلامت و تناسب اندام برنامه خود را با گسترش آن در دستگاه های پوشیدنی مجهز به Wear OS افزایش دهید.
یک ماژول Wear OS اضافه کنید
Android Studio یک جادوگر مفید برای اضافه کردن یک ماژول Wear OS به برنامه شما ارائه می دهد. در منوی File > New Module ، Wear OS را انتخاب کنید، همانطور که در تصویر زیر نشان داده شده است:
توجه به این نکته مهم است که حداقل SDK باید API 30 یا بالاتر باشد تا بتوانید از آخرین نسخه خدمات بهداشتی استفاده کنید. خدمات بهداشتی با پیکربندی خودکار حسگرهای سلامت، ردیابی معیارها و ثبت دادهها را آسانتر میکند.
پس از تکمیل ویزارد، پروژه خود را همگام کنید. پیکربندی Run زیر ظاهر می شود:
این به شما امکان می دهد ماژول Wear OS را روی یک دستگاه پوشیدنی اجرا کنید. شما دو گزینه دارید:
روی یک شبیه ساز اجرا کنید.
روی یک دستگاه واقعی اجرا کنید.
اجرای پیکربندی، برنامه را در شبیه ساز یا دستگاه Wear OS مستقر می کند و یک تجربه "سلام جهان" را نشان می دهد. این راهاندازی رابط کاربری اولیه است که از Compose for Wear OS برای شروع کار با برنامهتان استفاده میکند.
خدمات بهداشتی و Hilt را اضافه کنید
کتابخانه های زیر را در ماژول Wear OS خود ادغام کنید:
- خدمات بهداشتی : دسترسی به حسگرها و داده های ساعت را بسیار راحت و کارآمدتر می کند.
- Hilt : امکان تزریق و مدیریت موثر وابستگی را فراهم می کند.
مدیر خدمات بهداشتی را ایجاد کنید
برای اینکه استفاده از Health Services کمی راحتتر باشد، و یک API کوچکتر و روانتر را در معرض دید قرار دهید، میتوانید یک wrapper مانند زیر ایجاد کنید:
private const val TAG = "WATCHMAIN"
class HealthServicesManager(context: Context) {
private val measureClient = HealthServices.getClient(context).measureClient
suspend fun hasHeartRateCapability() = runCatching {
val capabilities = measureClient.getCapabilities()
(DataType.HEART_RATE_BPM in capabilities.supportedDataTypesMeasure)
}.getOrDefault(false)
/**
* Returns a cold flow. When activated, the flow will register a callback for heart rate data
* and start to emit messages. When the consuming coroutine is canceled, the measure callback
* is unregistered.
*
* [callbackFlow] creates a bridge between a callback-based API and Kotlin flows.
*/
@ExperimentalCoroutinesApi
fun heartRateMeasureFlow(): Flow<MeasureMessage> = callbackFlow {
val callback = object : MeasureCallback {
override fun onAvailabilityChanged(dataType: DeltaDataType<*, *>, availability: Availability) {
// Only send back DataTypeAvailability (not LocationAvailability)
if (availability is DataTypeAvailability) {
trySendBlocking(MeasureMessage.MeasureAvailability(availability))
}
}
override fun onDataReceived(data: DataPointContainer) {
val heartRateBpm = data.getData(DataType.HEART_RATE_BPM)
Log.d(TAG, "💓 Received heart rate: ${heartRateBpm.first().value}")
trySendBlocking(MeasureMessage.MeasureData(heartRateBpm))
}
}
Log.d(TAG, "⌛ Registering for data...")
measureClient.registerMeasureCallback(DataType.HEART_RATE_BPM, callback)
awaitClose {
Log.d(TAG, "👋 Unregistering for data")
runBlocking {
measureClient.unregisterMeasureCallback(DataType.HEART_RATE_BPM, callback)
}
}
}
}
sealed class MeasureMessage {
class MeasureAvailability(val availability: DataTypeAvailability) : MeasureMessage()
class MeasureData(val data: List<SampleDataPoint<Double>>) : MeasureMessage()
}
هنگامی که ماژول Hilt را برای مدیریت آن ایجاد کردید، با استفاده از قطعه زیر:
@Module
@InstallIn(SingletonComponent::class)
internal object DataModule {
@Provides
@Singleton
fun provideHealthServices(@ApplicationContext context: Context): HealthServicesManager = HealthServicesManager(context)
}
می توانید HealthServicesManager
به عنوان هر وابستگی دیگر به Hilt تزریق کنید.
HealthServicesManager
جدید یک متد heartRateMeasureFlow()
ارائه می کند که شنونده را برای مانیتور قلب ثبت می کند و داده های دریافتی را منتشر می کند.
به روز رسانی داده ها را در دستگاه های پوشیدنی فعال کنید
به روز رسانی داده های مربوط به تناسب اندام به مجوز BODY_SENSORS
نیاز دارد. اگر قبلاً این کار را نکردهاید، مجوز BODY_SENSORS
را در فایل مانیفست برنامه خود اعلام کنید. سپس، همانطور که در این قطعه نشان داده شده است، مجوز را درخواست کنید:
val permissionState = rememberPermissionState(
permission = Manifest.permission.BODY_SENSORS,
onPermissionResult = { granted -> /* do something */ }
)
[...]
if (permissionState.status.isGranted) {
// do something
} else {
permissionState.launchPermissionRequest()
}
اگر برنامه خود را روی یک دستگاه فیزیکی آزمایش می کنید، داده ها باید شروع به به روز رسانی کنند.
با شروع در Wear OS 4، شبیه سازها همچنین داده های تست را به صورت خودکار نشان می دهند. در نسخه های قبلی، می توانید جریان داده را از حسگر شبیه سازی کنید. در یک پنجره ترمینال، این دستور ADB را اجرا کنید:
adb shell am broadcast \
-a "whs.USE_SYNTHETIC_PROVIDERS" \
com.google.android.wearable.healthservices
برای مشاهده مقادیر مختلف ضربان قلب، تمرینات مختلف را شبیه سازی کنید. این دستور راه رفتن را شبیه سازی می کند:
adb shell am broadcast \
-a "whs.synthetic.user.START_WALKING" \
com.google.android.wearable.healthservices
این دستور اجرای را شبیه سازی می کند:
adb shell am broadcast \
-a "whs.synthetic.user.START_RUNNING" \
com.google.android.wearable.healthservices
برای توقف شبیه سازی داده ها، این دستور را اجرا کنید:
adb shell am broadcast -a \
"whs.USE_SENSOR_PROVIDERS" \
com.google.android.wearable.healthservices
اطلاعات ضربان قلب را بخوانید
با اعطای مجوز BODY_SENSORS
، میتوانید ضربان قلب کاربر ( heartRateMeasureFlow()
) را در HealthServicesManager
بخوانید. در رابط کاربری برنامه Wear OS، مقدار ضربان قلب فعلی ظاهر میشود که توسط حسگر دستگاه پوشیدنی اندازهگیری میشود.
در ViewModel
خود، همانطور که در قطعه زیر نشان داده شده است، با استفاده از شی جریان ضربان قلب شروع به جمع آوری داده کنید:
val hr: MutableState<Double> = mutableStateOf(0.0)
[...]
healthServicesManager
.heartRateMeasureFlow()
.takeWhile { enabled.value }
.collect { measureMessage ->
when (measureMessage) {
is MeasureData -> {
val latestHeartRateValue = measureMessage.data.last().value
hr.value = latestHeartRateValue
}
is MeasureAvailability -> availability.value =
measureMessage.availability
}
}
برای نمایش دادههای زنده در رابط کاربری برنامهتان از یک شیء قابل ترکیب مشابه موارد زیر استفاده کنید:
val heartRate by viewModel.hr
Text(
text = "Heart Rate: $heartRate",
style = MaterialTheme.typography.display1
)
ارسال داده به دستگاه دستی
برای ارسال داده های سلامتی و تناسب اندام به یک دستگاه دستی، از کلاس DataClient
در Health Services استفاده کنید. قطعه کد زیر نحوه ارسال داده های ضربان قلب را که قبلاً برنامه شما جمع آوری کرده است نشان می دهد:
class HealthServicesManager(context: Context) {
private val dataClient by lazy { Wearable.getDataClient(context) }
[...]
suspend fun sendToHandheldDevice(heartRate: Int) {
try {
val result = dataClient
.putDataItem(PutDataMapRequest
.create("/heartrate")
.apply { dataMap.putInt("heartrate", heartRate) }
.asPutDataRequest()
.setUrgent())
.await()
Log.d(TAG, "DataItem saved: $result")
} catch (cancellationException: CancellationException) {
throw cancellationException
} catch (exception: Exception) {
Log.d(TAG, "Saving DataItem failed: $exception")
}
}
}
داده ها را روی گوشی دریافت کنید
برای دریافت اطلاعات روی تلفن، یک WearableListenerService
ایجاد کنید:
@AndroidEntryPoint
class DataLayerListenerService : WearableListenerService() {
@Inject
lateinit var heartRateMonitor: HeartRateMonitor
override fun onDataChanged(dataEvents: DataEventBuffer) {
dataEvents.forEach { event ->
when (event.type) {
DataEvent.TYPE_CHANGED -> {
event.dataItem.run {
if (uri.path?.compareTo("/heartrate") == 0) {
val heartRate = DataMapItem.fromDataItem(this)
.dataMap.getInt(HR_KEY)
Log.d("DataLayerListenerService",
"New heart rate value received: $heartRate")
heartRateMonitor.send(heartRate)
}
}
}
DataEvent.TYPE_DELETED -> {
// DataItem deleted
}
}
}
}
}
پس از اتمام این مرحله، به چند جزئیات جالب توجه کنید:
- حاشیه نویسی
@AndroidEntryPoint
به ما امکان می دهد از Hilt در این کلاس استفاده کنیم -
@Inject lateinit var heartRateMonitor: HeartRateMonitor
در واقع یک وابستگی در این کلاس تزریق می کند - کلاس
onDataChanged()
را پیاده سازی می کند و مجموعه ای از رویدادها را دریافت می کند که می توانید آنها را تجزیه و استفاده کنید
منطق HeartRateMonitor
زیر به شما امکان می دهد مقادیر ضربان قلب دریافتی را به قسمت دیگری از پایگاه کد برنامه خود ارسال کنید:
class HeartRateMonitor {
private val datapoints = MutableSharedFlow<Int>(extraBufferCapacity = 10)
fun receive(): SharedFlow<Int> = datapoints.asSharedFlow()
fun send(hr: Int) {
datapoints.tryEmit(hr)
}
}
یک گذرگاه داده رویدادها را از متد onDataChanged()
دریافت می کند و با استفاده از SharedFlow
در دسترس ناظران داده قرار می دهد.
بیت پایانی اعلان Service
در برنامه تلفن AndroidManifest.xml
است:
<service
android:name=".DataLayerListenerService"
android:exported="true">
<intent-filter>
<!-- listeners receive events that match the action and data filters -->
<action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
<data
android:host="*"
android:pathPrefix="/heartrate"
android:scheme="wear" />
</intent-filter>
</service>
نمایش داده های بلادرنگ روی یک دستگاه دستی
در بخشی از برنامه شما که روی یک دستگاه دستی اجرا می شود، HeartRateMonitor
به سازنده مدل view خود تزریق کنید. این شی HeartRateMonitor
دادههای ضربان قلب را مشاهده میکند و در صورت نیاز بهروزرسانیهای UI را منتشر میکند.