You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Data Layer实现安卓手机向Wear OS手表传输图片,代码分Phone.kt、Watch.kt两个文件

安卓手机向Wear OS手表传输图片实现方案(Data Layer通信)

前置要求:手机端与手表端应用需保持相同applicationId、相同签名,两端均需添加Wearable Data Layer依赖

// 两端build.gradle都需添加该依赖
dependencies {
    implementation "com.google.android.gms:play-services-wearable:18.1.0"
}
// 手机端AndroidManifest需添加权限
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
// 手表端如需存储到公共目录需额外加存储权限,用内部存储可省略
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />

1. 手机端代码(Phone.kt)

完整覆盖「选中要传输的照片」+「发送照片到绑定手表」两个实现步骤:

import android.app.Activity
import android.content.Intent
import android.net.Uri
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.google.android.gms.wearable.PutDataMapRequest
import com.google.android.gms.wearable.Wearable
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await
import java.io.ByteArrayOutputStream
import java.io.InputStream

class PhoneActivity : AppCompatActivity() {
    private val IMAGE_PATH = "/image_transfer"
    private val IMAGE_KEY = "image_data"

    // 选图回调:实现步骤1 选中要传输的照片
    private val pickImageLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            result.data?.data?.let { imageUri ->
                val imageBytes = uriToByteArray(imageUri)
                imageBytes?.let { sendImageToWear(it) }
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 触发系统相册选图
        val pickIntent = Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
        pickImageLauncher.launch(pickIntent)
    }

    private fun uriToByteArray(uri: Uri): ByteArray? {
        return try {
            val inputStream: InputStream? = contentResolver.openInputStream(uri)
            val byteBuffer = ByteArrayOutputStream()
            inputStream?.use { input ->
                val buffer = ByteArray(1024)
                var len: Int
                while (input.read(buffer).also { len = it } != -1) {
                    byteBuffer.write(buffer, 0, len)
                }
            }
            byteBuffer.toByteArray()
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }

    // 实现步骤2 发送选中的照片到绑定的Wear OS手表
    private fun sendImageToWear(imageBytes: ByteArray) {
        CoroutineScope(Dispatchers.IO).launch {
            try {
                // 查询已绑定的手表节点
                val nodes = Wearable.getNodeClient(this@PhoneActivity).connectedNodes.await()
                if (nodes.isEmpty()) return@launch

                // 构造DataItem,加入时间戳确保每次传输都会触发同步
                val putDataMapRequest = PutDataMapRequest.create(IMAGE_PATH).apply {
                    dataMap.putByteArray(IMAGE_KEY, imageBytes)
                    dataMap.putLong("timestamp", System.currentTimeMillis())
                }
                val request = putDataMapRequest.asPutDataRequest()
                Wearable.getDataClient(this@PhoneActivity).putDataItem(request).await()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }
}

2. 手表端代码(Watch.kt)

完整覆盖「接收传输的图片」+「图片本地存储」两个实现步骤:

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.google.android.gms.wearable.DataClient
import com.google.android.gms.wearable.DataEvent
import com.google.android.gms.wearable.DataEventBuffer
import com.google.android.gms.wearable.Wearable
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

class WatchActivity : AppCompatActivity(), DataClient.OnDataChangedListener {
    private val IMAGE_PATH = "/image_transfer"
    private val IMAGE_KEY = "image_data"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    override fun onResume() {
        super.onResume()
        // 注册DataLayer数据变化监听
        Wearable.getDataClient(this).addListener(this)
    }

    override fun onPause() {
        super.onPause()
        Wearable.getDataClient(this).removeListener(this)
    }

    // 实现步骤3 接收手机端传输的图片
    override fun onDataChanged(dataEvents: DataEventBuffer) {
        dataEvents.forEach { event ->
            if (event.type == DataEvent.TYPE_CHANGED) {
                event.dataItem.takeIf { it.uri.path == IMAGE_PATH }?.let { dataItem ->
                    val dataMap = com.google.android.gms.wearable.DataMapItem.fromDataItem(dataItem).dataMap
                    dataMap.getByteArray(IMAGE_KEY)?.let { imageBytes ->
                        val bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size)
                        saveImageToLocal(bitmap)
                    }
                }
            }
        }
    }

    // 实现步骤4 将接收到的图片存储到手表本地
    private fun saveImageToLocal(bitmap: Bitmap) {
        CoroutineScope(Dispatchers.IO).launch {
            try {
                val fileName = "received_${System.currentTimeMillis()}.png"
                // 存储到应用内部存储,无需申请额外权限
                openFileOutput(fileName, MODE_PRIVATE).use { fos ->
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos)
                    fos.flush()
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }
}
  • 补充使用说明:
    • 传输前建议对图片做压缩处理,避免超过Data Layer单条100KB的大小限制
    • 若需要传输大体积图片,可拆分多块分别传输,接收端再拼接还原
    • 传输时需确保手机与手表保持正常绑定连接,两端应用都处于已安装状态

内容的提问来源于stack exchange,提问作者Oein0219

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 09:27:01