fdp 1 year ago
parent
commit
8c919c750b
  1. 43
      local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrHelper.kt
  2. 55
      local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureSpeechPlugin.kt
  3. 215
      local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/tools/RecordFile.kt
  4. 4
      local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt
  5. 57
      local_plugins/ota/android/src/main/kotlin/com/example/ota/OtaPlugin.kt

43
local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrHelper.kt

@ -57,7 +57,7 @@ class AzureAsrHelper(private val context: Context) {
// 音频处理 // 音频处理
private var microphoneStream: MicrophoneStream? = null private var microphoneStream: MicrophoneStream? = null
private var externalAudioStream: ExternalAudioPullStream? = null private var externalAudioStream: ExternalAudioPullStream? = null
// 音频模式管理 // 音频模式管理
private var audioManager: AudioManager? = null private var audioManager: AudioManager? = null
private var originalAudioMode = AudioManager.MODE_NORMAL private var originalAudioMode = AudioManager.MODE_NORMAL
@ -101,7 +101,7 @@ class AzureAsrHelper(private val context: Context) {
// 释放之前的资源 // 释放之前的资源
dispose() dispose()
// 初始化音频管理器 // 初始化音频管理器
audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
originalAudioMode = audioManager?.mode ?: AudioManager.MODE_NORMAL originalAudioMode = audioManager?.mode ?: AudioManager.MODE_NORMAL
@ -353,7 +353,7 @@ class AzureAsrHelper(private val context: Context) {
// 开始连续识别 // 开始连续识别
recognizer?.startContinuousRecognitionAsync() recognizer?.startContinuousRecognitionAsync()
isContinuousRecognitionActive = true isContinuousRecognitionActive = true
return true return true
} catch (e: Exception) { } catch (e: Exception) {
stopAudioProcessing() stopAudioProcessing()
@ -584,17 +584,18 @@ class AzureAsrHelper(private val context: Context) {
recordfile!!.closeFile(true) recordfile!!.closeFile(true)
recordfile!!.creatingFiles(filePath) recordfile!!.creatingFiles(filePath)
} }
/**
/**
* 移动文件到新路径 * 移动文件到新路径
*/ */
fun moveFile(sourcePath: String, destPath: String): Boolean { fun moveFile(sourcePath: String, destPath: String): Boolean {
Log.i(tag, "移动文件到新路径:") Log.i(tag, "移动文件到新路径:")
recordfile!!.moveFile(sourcePath,destPath) recordfile!!.moveFile(sourcePath, destPath)
return true return true
} }
@ -605,27 +606,27 @@ class AzureAsrHelper(private val context: Context) {
Log.i(tag, "重命名指定路径的音频文件:") Log.i(tag, "重命名指定路径的音频文件:")
recordfile!!.renameFile(filePath,newName) recordfile!!.renameFile(filePath, newName)
return true return true
} }
/** /**
* 停止录音 * 停止录音
*/ */
fun pauseRecord() { fun pauseRecord() {
Log.i(tag, "停止连续录音:") Log.i(tag, "停止连续录音:")
recordfile!!.isPause=true recordfile!!.isPause = true
} }
/** /**
* 关闭录音 * 关闭录音
*/ */
fun stopRecord(isSave:Boolean) { fun stopRecord(isSave: Boolean) {
Log.i(tag, "关闭录音:") Log.i(tag, "关闭录音:")
recordfile!!.isPause=false recordfile!!.isPause = false
recordfile!!.closeFile(isSave) recordfile!!.closeFile(isSave)
} }
@ -706,11 +707,11 @@ class AzureAsrHelper(private val context: Context) {
*/ */
private fun applyAudioEffects() { private fun applyAudioEffects() {
val sessionId = audioRecord?.audioSessionId ?: return val sessionId = audioRecord?.audioSessionId ?: return
try { try {
// 设置音频模式为通信模式 // 设置音频模式为通信模式
this@AzureAsrHelper.audioManager?.mode = AudioManager.MODE_IN_COMMUNICATION this@AzureAsrHelper.audioManager?.mode = AudioManager.MODE_IN_COMMUNICATION
// 启用声学回音消除 // 启用声学回音消除
if (AcousticEchoCanceler.isAvailable()) { if (AcousticEchoCanceler.isAvailable()) {
echoCanceler = AcousticEchoCanceler.create(sessionId) echoCanceler = AcousticEchoCanceler.create(sessionId)
@ -719,7 +720,7 @@ class AzureAsrHelper(private val context: Context) {
} else { } else {
Log.w(tag, "设备不支持声学回音消除") Log.w(tag, "设备不支持声学回音消除")
} }
// 启用噪声抑制 // 启用噪声抑制
if (NoiseSuppressor.isAvailable()) { if (NoiseSuppressor.isAvailable()) {
noiseSuppressor = NoiseSuppressor.create(sessionId) noiseSuppressor = NoiseSuppressor.create(sessionId)
@ -728,7 +729,7 @@ class AzureAsrHelper(private val context: Context) {
} else { } else {
Log.w(tag, "设备不支持噪声抑制") Log.w(tag, "设备不支持噪声抑制")
} }
// 启用自动增益控制 // 启用自动增益控制
if (AutomaticGainControl.isAvailable()) { if (AutomaticGainControl.isAvailable()) {
automaticGainControl = AutomaticGainControl.create(sessionId) automaticGainControl = AutomaticGainControl.create(sessionId)
@ -737,7 +738,7 @@ class AzureAsrHelper(private val context: Context) {
} else { } else {
Log.w(tag, "设备不支持自动增益控制") Log.w(tag, "设备不支持自动增益控制")
} }
Log.i(tag, "回音消除和音频增强功能已全部启用") Log.i(tag, "回音消除和音频增强功能已全部启用")
} catch (e: Exception) { } catch (e: Exception) {
Log.e(tag, "设置音频效果失败: ${e.message}") Log.e(tag, "设置音频效果失败: ${e.message}")
@ -795,21 +796,21 @@ class AzureAsrHelper(private val context: Context) {
it.release() it.release()
echoCanceler = null echoCanceler = null
} }
// 释放噪声抑制器 // 释放噪声抑制器
noiseSuppressor?.let { noiseSuppressor?.let {
it.enabled = false it.enabled = false
it.release() it.release()
noiseSuppressor = null noiseSuppressor = null
} }
// 释放自动增益控制 // 释放自动增益控制
automaticGainControl?.let { automaticGainControl?.let {
it.enabled = false it.enabled = false
it.release() it.release()
automaticGainControl = null automaticGainControl = null
} }
// 恢复音频模式 // 恢复音频模式
this@AzureAsrHelper.audioManager?.mode = this@AzureAsrHelper.originalAudioMode this@AzureAsrHelper.audioManager?.mode = this@AzureAsrHelper.originalAudioMode

55
local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureSpeechPlugin.kt

@ -11,7 +11,6 @@ import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.EventChannel import io.flutter.plugin.common.EventChannel
import com.microsoft.cognitiveservices.speech.audio.*
import com.deep_voice.speech.tts.TtsEvent import com.deep_voice.speech.tts.TtsEvent
import com.deep_voice.speech.tts.TtsEventListener import com.deep_voice.speech.tts.TtsEventListener
import com.deep_voice.speech.tts.TtsEventType import com.deep_voice.speech.tts.TtsEventType
@ -355,50 +354,54 @@ class AzureSpeechPlugin : BleService.Callback, FlutterPlugin {
} }
"renameFile" -> { "renameFile" -> {
val filePath = call.argument<String>("filePath")?: "" val filePath = call.argument<String>("filePath") ?: ""
val newName = call.argument<String>("newName")?: "" val newName = call.argument<String>("newName") ?: ""
try { try {
FileLogger.d(tag, "音频文件名称为: ${filePath}") // FileLogger.d(tag, "音频文件名称为: ${filePath}") //
azureAsrHelper.renameFile(filePath,newName) azureAsrHelper.renameFile(filePath, newName)
result.success(true) result.success(true)
} catch (e: Exception) { } catch (e: Exception) {
result.error("ENABLERECORD_ERROR", e.message, null) result.error("ENABLERECORD_ERROR", e.message, null)
} }
} }
"moveFile" -> {
val sourcePath = call.argument<String>("sourcePath")?: "" "moveFile" -> {
val destPath = call.argument<String>("destPath")?: "" val sourcePath = call.argument<String>("sourcePath") ?: ""
val destPath = call.argument<String>("destPath") ?: ""
try { try {
FileLogger.d(tag, "音频文件名称为: ${sourcePath}") // FileLogger.d(tag, "音频文件名称为: ${sourcePath}") //
azureAsrHelper.moveFile(sourcePath,destPath) azureAsrHelper.moveFile(sourcePath, destPath)
result.success(true) result.success(true)
} catch (e: Exception) { } catch (e: Exception) {
result.error("ENABLERECORD_ERROR", e.message, null) result.error("ENABLERECORD_ERROR", e.message, null)
} }
} }
"enableRecord" -> {
val filePath = call.argument<String>("filePath")?: "" "enableRecord" -> {
val filePath = call.argument<String>("filePath") ?: ""
try { try {
FileLogger.d(tag, "音频文件名称为: ${filePath}") // FileLogger.d(tag, "音频文件名称为: ${filePath}") //
azureAsrHelper.enableRecord(filePath) azureAsrHelper.enableRecord(filePath)
result.success(true) result.success(true)
} catch (e: Exception) { } catch (e: Exception) {
result.error("ENABLERECORD_ERROR", e.message, null) result.error("ENABLERECORD_ERROR", e.message, null)
} }
} }
"pauseRecord" -> {
"pauseRecord" -> {
azureAsrHelper.pauseRecord() azureAsrHelper.pauseRecord()
result.success(true) result.success(true)
} }
"stopRecord" -> { "stopRecord" -> {
val isSave = call.argument<Boolean>("isSave")?:false val isSave = call.argument<Boolean>("isSave") ?: false
try { try {
azureAsrHelper.stopRecord(isSave) azureAsrHelper.stopRecord(isSave)
result.success(true) result.success(true)
} catch (e: Exception) { } catch (e: Exception) {
result.error("ENABLERECORD_ERROR", e.message, null) result.error("ENABLERECORD_ERROR", e.message, null)
} }
} }

215
local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/tools/RecordFile.kt

@ -1,4 +1,5 @@
package com.yunqiinnovation.azure_speech.tools package com.yunqiinnovation.azure_speech.tools
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
import java.io.RandomAccessFile import java.io.RandomAccessFile
@ -8,41 +9,41 @@ import java.io.FileInputStream
import java.util.concurrent.LinkedBlockingQueue import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
object RecordFile { object RecordFile {
private var currentAudioFile: File? = null private var currentAudioFile: File? = null
private var fos: FileOutputStream? = null private var fos: FileOutputStream? = null
// 新增:用于异步写入的队列和线程 // 新增:用于异步写入的队列和线程
private val writeQueue = LinkedBlockingQueue<ByteArray>() private val writeQueue = LinkedBlockingQueue<ByteArray>()
private val isWriting = AtomicBoolean(false) private val isWriting = AtomicBoolean(false)
private var writeThread: Thread? = null private var writeThread: Thread? = null
// 用于存储音频数据的缓冲区 // 用于存储音频数据的缓冲区
private val dataBuffer = mutableListOf<ByteArray>() private val dataBuffer = mutableListOf<ByteArray>()
private var totalBytesWritten = 0 private var totalBytesWritten = 0
// 音频配置 // 音频配置
private val sampleRate = 16000 private val sampleRate = 16000
// 新增:用于存储最后成功保存的文件 // 新增:用于存储最后成功保存的文件
private var lastSavedFile: File? = null private var lastSavedFile: File? = null
private var lastFileTimestamp: String = "" private var lastFileTimestamp: String = ""
var isPause = false var isPause = false
var fileName = "" var fileName = ""
// 修改:添加 filePath 参数 // 修改:添加 filePath 参数
internal fun creatingFiles(filePath: String) { internal fun creatingFiles(filePath: String) {
if (fos != null || currentAudioFile != null) { if (fos != null || currentAudioFile != null) {
return return
} }
val file = File(filePath) val file = File(filePath)
val parentDir = file.parentFile val parentDir = file.parentFile
if (!parentDir.exists()) { if (!parentDir.exists()) {
parentDir.mkdirs() parentDir.mkdirs()
} }
currentAudioFile = file currentAudioFile = file
currentAudioFile?.createNewFile() currentAudioFile?.createNewFile()
@ -56,59 +57,59 @@ import java.util.concurrent.atomic.AtomicBoolean
} }
// 新增:启动写入线程 // 新增:启动写入线程
private fun startWriteThread() { private fun startWriteThread() {
if (isWriting.get()) return if (isWriting.get()) return
isWriting.set(true) isWriting.set(true)
writeThread = Thread { writeThread = Thread {
try { try {
while (isWriting.get() || writeQueue.isNotEmpty()) { while (isWriting.get() || writeQueue.isNotEmpty()) {
val data = writeQueue.poll() ?: continue val data = writeQueue.poll() ?: continue
fos?.write(data) fos?.write(data)
}
} catch (e: Exception) {
Log.e("tag", "异步写入音频数据失败: ${e.message}")
} }
} catch (e: Exception) {
Log.e("tag", "异步写入音频数据失败: ${e.message}")
} }
writeThread?.start()
} }
writeThread?.start()
}
/** /**
* 保存音频数据到 WAV 文件(异步) * 保存音频数据到 WAV 文件(异步)
*/ */
internal fun saveAudioDataToWav(buffer: ByteArray) { internal fun saveAudioDataToWav(buffer: ByteArray) {
if (fos == null || currentAudioFile == null) return if (fos == null || currentAudioFile == null) return
// 放入队列,由写线程写入 // 放入队列,由写线程写入
writeQueue.offer(buffer.copyOf()) writeQueue.offer(buffer.copyOf())
totalBytesWritten += buffer.size totalBytesWritten += buffer.size
} }
// 更新文件头生成(修正RIFF长度计算) // 更新文件头生成(修正RIFF长度计算)
private fun generateWavHeader(dataLength: Int): ByteArray { private fun generateWavHeader(dataLength: Int): ByteArray {
val totalLength = 36 + dataLength // RIFF块总长度 = 头部36字节 + 音频数据 val totalLength = 36 + dataLength // RIFF块总长度 = 头部36字节 + 音频数据
val byteRate = sampleRate * 2 * 1 // 采样率 * 字节/样本 * 通道数 val byteRate = sampleRate * 2 * 1 // 采样率 * 字节/样本 * 通道数
return byteArrayOf( return byteArrayOf(
'R'.code.toByte(), 'I'.code.toByte(), 'F'.code.toByte(), 'F'.code.toByte(), 'R'.code.toByte(), 'I'.code.toByte(), 'F'.code.toByte(), 'F'.code.toByte(),
(totalLength and 0xFF).toByte(), ((totalLength shr 8) and 0xFF).toByte(), (totalLength and 0xFF).toByte(), ((totalLength shr 8) and 0xFF).toByte(),
((totalLength shr 16) and 0xFF).toByte(), ((totalLength shr 24) and 0xFF).toByte(), ((totalLength shr 16) and 0xFF).toByte(), ((totalLength shr 24) and 0xFF).toByte(),
'W'.code.toByte(), 'A'.code.toByte(), 'V'.code.toByte(), 'E'.code.toByte(), 'W'.code.toByte(), 'A'.code.toByte(), 'V'.code.toByte(), 'E'.code.toByte(),
'f'.code.toByte(), 'm'.code.toByte(), 't'.code.toByte(), ' '.code.toByte(), 'f'.code.toByte(), 'm'.code.toByte(), 't'.code.toByte(), ' '.code.toByte(),
16, 0, 0, 0, // PCM头长度 16, 0, 0, 0, // PCM头长度
1, 0, // PCM格式 1, 0, // PCM格式
1, 0, // 单声道 1, 0, // 单声道
(sampleRate and 0xFF).toByte(), ((sampleRate shr 8) and 0xFF).toByte(), 0, 0, // 采样率 (sampleRate and 0xFF).toByte(), ((sampleRate shr 8) and 0xFF).toByte(), 0, 0, // 采样率
(byteRate and 0xFF).toByte(), ((byteRate shr 8) and 0xFF).toByte(), 0, 0, // 字节率 (byteRate and 0xFF).toByte(), ((byteRate shr 8) and 0xFF).toByte(), 0, 0, // 字节率
2, 0, // 块对齐 (通道数 * 样本位数/8) 2, 0, // 块对齐 (通道数 * 样本位数/8)
16, 0, // 样本位数 16, 0, // 样本位数
'd'.code.toByte(), 'a'.code.toByte(), 't'.code.toByte(), 'a'.code.toByte(), 'd'.code.toByte(), 'a'.code.toByte(), 't'.code.toByte(), 'a'.code.toByte(),
(dataLength and 0xFF).toByte(), ((dataLength shr 8) and 0xFF).toByte(), (dataLength and 0xFF).toByte(), ((dataLength shr 8) and 0xFF).toByte(),
((dataLength shr 16) and 0xFF).toByte(), ((dataLength shr 24) and 0xFF).toByte() ((dataLength shr 16) and 0xFF).toByte(), ((dataLength shr 24) and 0xFF).toByte()
) )
} }
/** /**
* 重命名指定路径的音频文件 * 重命名指定路径的音频文件
* @param filePath 要重命名的文件完整路径 * @param filePath 要重命名的文件完整路径
* @param newName 新的文件名(不含扩展名) * @param newName 新的文件名(不含扩展名)
@ -116,28 +117,28 @@ import java.util.concurrent.atomic.AtomicBoolean
*/ */
internal fun renameFile(filePath: String, newName: String): Boolean { internal fun renameFile(filePath: String, newName: String): Boolean {
val sourceFile = File(filePath) val sourceFile = File(filePath)
// 验证源文件存在 // 验证源文件存在
if (!sourceFile.exists()) { if (!sourceFile.exists()) {
Log.w("tag", "重命名失败: 文件不存在 $filePath") Log.w("tag", "重命名失败: 文件不存在 $filePath")
return false return false
} }
// 防止重命名正在录制的文件 // 防止重命名正在录制的文件
if (sourceFile == currentAudioFile) { if (sourceFile == currentAudioFile) {
Log.w("tag", "重命名失败: 不能重命名正在录制的文件") Log.w("tag", "重命名失败: 不能重命名正在录制的文件")
return false return false
} }
val parentDir = sourceFile.parentFile val parentDir = sourceFile.parentFile
val newFile = File(parentDir, "$newName.wav") // 保持.wav扩展名 val newFile = File(parentDir, "$newName.wav") // 保持.wav扩展名
// 处理目标文件已存在的情况 // 处理目标文件已存在的情况
if (newFile.exists()) { if (newFile.exists()) {
Log.w("tag", "重命名失败: 目标文件已存在 ${newFile.absolutePath}") Log.w("tag", "重命名失败: 目标文件已存在 ${newFile.absolutePath}")
return false return false
} }
// 执行重命名 // 执行重命名
return try { return try {
val success = sourceFile.renameTo(newFile) val success = sourceFile.renameTo(newFile)
@ -156,7 +157,8 @@ import java.util.concurrent.atomic.AtomicBoolean
false false
} }
} }
/**
/**
* 移动文件到新路径 * 移动文件到新路径
* @param sourcePath 原始文件完整路径 * @param sourcePath 原始文件完整路径
* @param destPath 目标文件完整路径 * @param destPath 目标文件完整路径
@ -165,25 +167,25 @@ import java.util.concurrent.atomic.AtomicBoolean
internal fun moveFile(sourcePath: String, destPath: String): Boolean { internal fun moveFile(sourcePath: String, destPath: String): Boolean {
val sourceFile = File(sourcePath) val sourceFile = File(sourcePath)
val destFile = File(destPath) val destFile = File(destPath)
if (!sourceFile.exists()) { if (!sourceFile.exists()) {
Log.w("tag", "移动失败: 源文件不存在 ${sourceFile.absolutePath}") Log.w("tag", "移动失败: 源文件不存在 ${sourceFile.absolutePath}")
return false return false
} }
// 确保目标目录存在 // 确保目标目录存在
val destDir = destFile.parentFile val destDir = destFile.parentFile
if (!destDir.exists() && !destDir.mkdirs()) { if (!destDir.exists() && !destDir.mkdirs()) {
Log.w("tag", "移动失败: 无法创建目标目录 ${destDir.absolutePath}") Log.w("tag", "移动失败: 无法创建目标目录 ${destDir.absolutePath}")
return false return false
} }
// 删除已存在的目标文件 // 删除已存在的目标文件
if (destFile.exists() && !destFile.delete()) { if (destFile.exists() && !destFile.delete()) {
Log.w("tag", "移动失败: 无法覆盖已存在文件 ${destFile.absolutePath}") Log.w("tag", "移动失败: 无法覆盖已存在文件 ${destFile.absolutePath}")
return false return false
} }
return try { return try {
// 使用renameTo尝试移动(同分区最快) // 使用renameTo尝试移动(同分区最快)
if (sourceFile.renameTo(destFile)) { if (sourceFile.renameTo(destFile)) {
@ -213,39 +215,40 @@ import java.util.concurrent.atomic.AtomicBoolean
false false
} }
} }
internal fun closeFile( isSave:Boolean): Boolean {
try { internal fun closeFile(isSave: Boolean): Boolean {
if (fos == null || currentAudioFile == null) { try {
if (fos == null || currentAudioFile == null) {
return false
}
isWriting.set(false)
writeThread?.join(500)
fos?.close()
currentAudioFile?.let { file ->
if (file.length() <= 44 || isSave == false) {
file.delete()
Log.d("tag", "音频文件过小已删除: ${file.absolutePath}")
return false return false
} } else {
isWriting.set(false) RandomAccessFile(file, "rw").use { raf ->
writeThread?.join(500) raf.seek(0)
fos?.close() raf.write(generateWavHeader(totalBytesWritten))
currentAudioFile?.let { file ->
if (file.length() <= 44||isSave==false) {
file.delete()
Log.d("tag", "音频文件过小已删除: ${file.absolutePath}")
return false
} else {
RandomAccessFile(file, "rw").use { raf ->
raf.seek(0)
raf.write(generateWavHeader(totalBytesWritten))
}
Log.d("tag", "音频文件保存完成: ${file.absolutePath}")
// 保存成功文件引用
lastSavedFile = file
return true
} }
Log.d("tag", "音频文件保存完成: ${file.absolutePath}")
// 保存成功文件引用
lastSavedFile = file
return true
} }
} catch (e: Exception) {
Log.e("tag", "更新WAV文件头失败: ${e.message}")
return false
} finally {
fos = null
currentAudioFile = null
} }
} catch (e: Exception) {
Log.e("tag", "更新WAV文件头失败: ${e.message}")
return false return false
} finally {
fos = null
currentAudioFile = null
} }
} return false
}
}

4
local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt

@ -16,14 +16,10 @@ import com.jieli.jl_audio_decode.exceptions.OpusException
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
import java.io.RandomAccessFile
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
import java.util.concurrent.BlockingQueue
import java.util.concurrent.LinkedBlockingQueue import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.TimeUnit
import android.os.Handler import android.os.Handler
import android.os.HandlerThread
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import android.util.Log import android.util.Log
/** /**

57
local_plugins/ota/android/src/main/kotlin/com/example/ota/OtaPlugin.kt

@ -268,37 +268,36 @@ class OtaPlugin : BleService.Callback, FlutterPlugin, MethodCallHandler {
streamSink = null streamSink = null
} }
}) })
} }
override fun onMethodCall(call: MethodCall, result: Result) { override fun onMethodCall(call: MethodCall, result: Result) {
if (call.method == "init") { if (call.method == "init") {
// 初始化 otaManager 和 bluetoothHelper // 初始化 otaManager 和 bluetoothHelper
ConfigHelper.initialize(context) ConfigHelper.initialize(context)
otaManager = OTAManager(context) otaManager = OTAManager(context)
bluetoothHelper = BluetoothHelper(context) bluetoothHelper = BluetoothHelper(context)
// 如果需要额外的初始化逻辑,请在这里添加 // 如果需要额外的初始化逻辑,请在这里添加
otaManager.registerBluetoothCallback(bluetoothCallback) otaManager.registerBluetoothCallback(bluetoothCallback)
// 初始化BleService // 初始化BleService
// 2. 初始化BleService并注册回调 // 2. 初始化BleService并注册回调
if (BleService.initialize(context)) { if (BleService.initialize(context)) {
if (BleService.addCallback(this)) { if (BleService.addCallback(this)) {
isRegisteredToBle = true isRegisteredToBle = true
Log.d(TAG, "已注册BLE回调") Log.d(TAG, "已注册BLE回调")
} else {
Log.w(TAG, "BLE回调注册失败")
}
} else { } else {
Log.w(TAG, "BLE回调注册失败") Log.e(TAG, "BLE服务初始化失败")
} }
} else {
Log.e(TAG, "BLE服务初始化失败")
}
Log.i("TAG", "onAttachedToEngine") Log.i("TAG", "onAttachedToEngine")
result.success("") result.success("")
} } else if (call.method == "startUpgrading") {
else if (call.method == "startUpgrading") {
Log.d("TAG", "startUpgrading") Log.d("TAG", "startUpgrading")
// 接收传入的参数 // 接收传入的参数
val arguments = call.arguments as? Map<String, Any> val arguments = call.arguments as? Map<String, Any>
@ -331,16 +330,16 @@ class OtaPlugin : BleService.Callback, FlutterPlugin, MethodCallHandler {
BleService.isEnterOta = false BleService.isEnterOta = false
} }
result.success("") result.success("")
} else if (call.method == "onOtaClose") { } else if (call.method == "onOtaClose") {
BleService.isEnterOta = false BleService.isEnterOta = false
isDisconnect = false isDisconnect = false
otaManager?.bluetoothHelper?.stopScan() otaManager?.bluetoothHelper?.stopScan()
otaManager?.bluetoothHelper?.disconnectDevice(otaDevice) otaManager?.bluetoothHelper?.disconnectDevice(otaDevice)
result.success("") result.success("")
} else { } else {
result.notImplemented() result.notImplemented()
} }

Loading…
Cancel
Save