一、技术选型说明
-
蓝牙协议选择
- 大文件传输:使用 Classic Bluetooth RFCOMM Socket(适合 1MB 以上文件)
- 小数据包传输:使用 BLE(适合实时性要求高的场景)
-
Jetpack 组件整合
gradle
dependencies {
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.6.2"
implementation "androidx.work:work-runtime-ktx:2.8.1"
}
二、核心实现步骤
1. 权限配置
xml
<!-- Android 12+ 需要新增权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<!-- 文件传输需要 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2. 设备发现与配对
示例代码:
kotlin
class BluetoothViewModel : ViewModel() {
private val _devices = MutableStateFlow<List<BluetoothDevice>>(emptyList())
val devices: StateFlow<List<BluetoothDevice>> = _devices
private val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
when(intent.action) {
BluetoothDevice.ACTION_FOUND -> {
val device = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)
device?.let {
_devices.update { current -> current + it }
}
}
}
}
}
fun startDiscovery(context: Context) {
context.registerReceiver(receiver, IntentFilter(BluetoothDevice.ACTION_FOUND))
BluetoothAdapter.getDefaultAdapter()?.startDiscovery()
}
fun stopDiscovery(context: Context) {
BluetoothAdapter.getDefaultAdapter()?.cancelDiscovery()
context.unregisterReceiver(receiver)
}
}
3、文件传输核心实现
示例代码:
kotlin
class FileTransferService : Service() {
private val channelId = "BluetoothTransfer"
private var socket: BluetoothSocket? = null
override fun onBind(intent: Intent?): IBinder? = null
override fun onCreate() {
createNotificationChannel()
startForeground(1, createNotification())
}
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
channelId,
"File Transfer",
NotificationManager.IMPORTANCE_LOW
)
getSystemService(NotificationManager::class.java)
.createNotificationChannel(channel)
}
}
private fun createNotification() = NotificationCompat.Builder(this, channelId)
.setContentTitle("文件传输中")
.setSmallIcon(R.drawable.ic_transfer)
.build()
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
intent?.getParcelableExtra<BluetoothDevice>("device")?.let { device ->
CoroutineScope(Dispatchers.IO).launch {
try {
socket = device.createRfcommSocketToServiceRecord(
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")
)
socket?.connect()
transferFile(intent.getParcelableExtra("fileUri")!!)
} catch (e: IOException) {
Log.e("BluetoothTransfer", "Transfer failed", e)
} finally {
socket?.close()
stopSelf()
}
}
}
return START_NOT_STICKY
}
private fun transferFile(uri: Uri) {
contentResolver.openInputStream(uri)?.use { input ->
socket?.outputStream?.use { output ->
val buffer = ByteArray(8192)
var bytesRead: Int
while (input.read(buffer).also { bytesRead = it } != -1) {
output.write(buffer, 0, bytesRead)
output.flush()
}
}
}
}
}
4、使用 WorkManager 管理传输任务
示例代码:
kotlin
class BluetoothTransferWorker(
context: Context,
params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
val device = inputData.getParcelable<BluetoothDevice>("device")!!
val fileUri = inputData.getString("fileUri")!!.toUri()
return try {
withContext(Dispatchers.IO) {
val socket = device.createRfcommSocketToServiceRecord(
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")
)
socket.connect()
applicationContext.contentResolver.openInputStream(fileUri)?.use { input ->
socket.outputStream.use { output ->
input.copyTo(output)
}
}
Result.success()
}
} catch (e: Exception) {
Result.retry()
}
}
}
// 在 ViewModel 中启动传输
fun startTransfer(device: BluetoothDevice, uri: Uri) {
val request = OneTimeWorkRequestBuilder<BluetoothTransferWorker>()
.setInputData(workDataOf(
"device" to device,
"fileUri" to uri.toString()
))
.build()
WorkManager.getInstance(context).enqueue(request)
}
三、优化实践
1. 传输进度监控
示例代码:
kotlin
class TransferProgressMonitor(private val callback: (Float) -> Unit) : FileTransferService() {
override fun transferFile(uri: Uri) {
val totalBytes = contentResolver.openFileDescriptor(uri, "r")?.use {
it.statSize
} ?: 0L
var transferredBytes = 0L
contentResolver.openInputStream(uri)?.use { input ->
socket?.outputStream?.use { output ->
val buffer = ByteArray(8192)
var bytesRead: Int
while (input.read(buffer).also { bytesRead = it } != -1) {
output.write(buffer, 0, bytesRead)
transferredBytes += bytesRead
val progress = transferredBytes.toFloat() / totalBytes
callback(progress.coerceIn(0f, 1f))
}
}
}
}
}
2. 断点续传实现
示例代码:
kotlin
class ResumableTransferWorker : CoroutineWorker(...) {
override suspend fun doWork(): Result {
val sessionFile = File(cacheDir, "transfer_session")
var session = sessionFile.readSession() ?: TransferSession()
try {
while (session.transferred < session.totalSize) {
transferChunk(session)
sessionFile.writeSession(session)
}
return Result.success()
} catch (e: Exception) {
return if (runAttemptCount < 3) Result.retry() else Result.failure()
}
}
private suspend fun transferChunk(session: TransferSession) {
// 实现分块传输逻辑
}
}
data class TransferSession(
val totalSize: Long = 0,
val transferred: Long = 0
)
四、注意事项
1、版本兼容处理
kotlin
fun checkBluetoothAvailability(): Boolean {
return when {
Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT -> {
// 4.4 以下版本不支持 BLE
false
}
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
// Android 12+ 需要检查新权限
checkSelfPermission(BluetoothAdapter.ACTION_REQUEST_ENABLE)
}
else -> true
}
}
2、传输稳定性优化
- 设置合理的 MTU 大小(512 bytes 为推荐值)
- 实现 ACK 确认机制
- 添加数据校验(CRC32/MD5)
3、典型错误处理
示例代码:
kotlin
fun handleTransferError(exception: Exception) {
when (exception) {
is SocketTimeoutException -> showError("连接超时")
is IOException -> showError("IO 异常")
is SecurityException -> requestPermissions()
else -> showError("未知错误")
}
}
五、扩展功能建议
1、多设备并行传输
示例代码:
kotlin
class ParallelTransferManager {
private val transfers = ConcurrentHashMap<String, Job>()
fun addTransfer(device: BluetoothDevice, file: File) {
transfers[device.address] = CoroutineScope(Dispatchers.IO).launch {
// 实现并行传输逻辑
}
}
}
2、文件加密传输
示例代码:
kotlin
fun encryptData(data: ByteArray, key: SecretKey): ByteArray {
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
cipher.init(Cipher.ENCRYPT_MODE, key)
return cipher.doFinal(data)
}
3、传输历史记录
示例代码:
kotlin
@Entity
data class TransferRecord(
@PrimaryKey val id: String,
val fileName: String,
val deviceName: String,
val timestamp: Long,
val success: Boolean
)
@Dao
interface TransferDao {
@Query("SELECT * FROM TransferRecord ORDER BY timestamp DESC")
fun getAll(): Flow<List<TransferRecord>>
}
本方案结合了传统蓝牙的文件传输能力与 Jetpack 组件的现代化架构优势,实现了:
- 完整的生命周期管理
- 后台传输可靠性
- 进度可视化
- 断点续传能力
- 完善的错误处理机制
建议根据实际业务需求选择合适的技术组合,对于需要兼容旧设备的场景可优先使用经典蓝牙方案,对于低功耗需求场景可考虑 BLE 分片传输方案。