IOS开发2

This commit is contained in:
2026-03-18 19:35:48 +08:00
parent 7c39810338
commit 8d02f5a5e2
10 changed files with 114 additions and 350 deletions
@@ -439,7 +439,6 @@
8EED65A5198A626B000A4449 /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; };
8EED65A7198A6273000A4449 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; };
A832515F2F67A4C2001DCF21 /* IJKMediaFrameworkWithSSL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IJKMediaFrameworkWithSSL.framework; path = ../SDK/Libs/IJKMediaFrameworkWithSSL.framework; sourceTree = "<group>"; };
A86BA3852F63EBE400AF9A88 /* DCloudUTSFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DCloudUTSFoundation.framework; path = ../SDK/Libs/DCloudUTSFoundation.framework; sourceTree = "<group>"; };
A87E07812F6929AE00276C29 /* DCloudUTSFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = DCloudUTSFoundation.framework; sourceTree = "<group>"; };
A87E07882F692EFF00276C29 /* DCUniBase.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = DCUniBase.framework; sourceTree = "<group>"; };
A88BFB312E2600AC00E932EB /* DCSVProgressHUD.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = DCSVProgressHUD.bundle; path = ../SDK/Bundles/DCSVProgressHUD.bundle; sourceTree = "<group>"; };
@@ -862,7 +861,6 @@
isa = PBXGroup;
children = (
A832515F2F67A4C2001DCF21 /* IJKMediaFrameworkWithSSL.framework */,
A86BA3852F63EBE400AF9A88 /* DCloudUTSFoundation.framework */,
A8A511A32EEAAD4500D15560 /* libbz2.tbd */,
A8A511A12EEAAD0500D15560 /* QuartzCore.framework */,
A88BFB3A2E26030300E932EB /* Masonry.framework */,
@@ -3970,226 +3970,6 @@
}
]
},
{
"kind": "Var",
"name": "reuseInt32Array",
"printedName": "reuseInt32Array",
"children": [
{
"kind": "TypeNominal",
"name": "Optional",
"printedName": "DCloudUTSFoundation.Int32Array?",
"children": [
{
"kind": "TypeNominal",
"name": "Int32Array",
"printedName": "DCloudUTSFoundation.Int32Array",
"usr": "c:@M@DCloudUTSFoundation@objc(cs)Int32Array"
}
],
"usr": "s:Sq"
}
],
"declKind": "Var",
"usr": "s:20unimoduleTyRecording15reuseInt32Array19DCloudUTSFoundation0eF0CSgvp",
"mangledName": "$s20unimoduleTyRecording15reuseInt32Array19DCloudUTSFoundation0eF0CSgvp",
"moduleName": "unimoduleTyRecording",
"declAttributes": [
"HasInitialValue",
"HasStorage",
"AccessControl"
],
"hasStorage": true,
"accessors": [
{
"kind": "Accessor",
"name": "Get",
"printedName": "Get()",
"children": [
{
"kind": "TypeNominal",
"name": "Optional",
"printedName": "DCloudUTSFoundation.Int32Array?",
"children": [
{
"kind": "TypeNominal",
"name": "Int32Array",
"printedName": "DCloudUTSFoundation.Int32Array",
"usr": "c:@M@DCloudUTSFoundation@objc(cs)Int32Array"
}
],
"usr": "s:Sq"
}
],
"declKind": "Accessor",
"usr": "s:20unimoduleTyRecording15reuseInt32Array19DCloudUTSFoundation0eF0CSgvg",
"mangledName": "$s20unimoduleTyRecording15reuseInt32Array19DCloudUTSFoundation0eF0CSgvg",
"moduleName": "unimoduleTyRecording",
"implicit": true,
"accessorKind": "get"
},
{
"kind": "Accessor",
"name": "Set",
"printedName": "Set()",
"children": [
{
"kind": "TypeNominal",
"name": "Void",
"printedName": "()"
},
{
"kind": "TypeNominal",
"name": "Optional",
"printedName": "DCloudUTSFoundation.Int32Array?",
"children": [
{
"kind": "TypeNominal",
"name": "Int32Array",
"printedName": "DCloudUTSFoundation.Int32Array",
"usr": "c:@M@DCloudUTSFoundation@objc(cs)Int32Array"
}
],
"usr": "s:Sq"
}
],
"declKind": "Accessor",
"usr": "s:20unimoduleTyRecording15reuseInt32Array19DCloudUTSFoundation0eF0CSgvs",
"mangledName": "$s20unimoduleTyRecording15reuseInt32Array19DCloudUTSFoundation0eF0CSgvs",
"moduleName": "unimoduleTyRecording",
"implicit": true,
"accessorKind": "set"
},
{
"kind": "Accessor",
"name": "Modify",
"printedName": "Modify()",
"children": [
{
"kind": "TypeNominal",
"name": "Void",
"printedName": "()"
}
],
"declKind": "Accessor",
"usr": "s:20unimoduleTyRecording15reuseInt32Array19DCloudUTSFoundation0eF0CSgvM",
"mangledName": "$s20unimoduleTyRecording15reuseInt32Array19DCloudUTSFoundation0eF0CSgvM",
"moduleName": "unimoduleTyRecording",
"implicit": true,
"accessorKind": "_modify"
}
]
},
{
"kind": "Var",
"name": "recordedPCMData",
"printedName": "recordedPCMData",
"children": [
{
"kind": "TypeNominal",
"name": "Array",
"printedName": "[Swift.UInt8]",
"children": [
{
"kind": "TypeNominal",
"name": "UInt8",
"printedName": "Swift.UInt8",
"usr": "s:s5UInt8V"
}
],
"usr": "s:Sa"
}
],
"declKind": "Var",
"usr": "s:20unimoduleTyRecording15recordedPCMDataSays5UInt8VGvp",
"mangledName": "$s20unimoduleTyRecording15recordedPCMDataSays5UInt8VGvp",
"moduleName": "unimoduleTyRecording",
"declAttributes": [
"HasInitialValue",
"HasStorage",
"AccessControl"
],
"hasStorage": true,
"accessors": [
{
"kind": "Accessor",
"name": "Get",
"printedName": "Get()",
"children": [
{
"kind": "TypeNominal",
"name": "Array",
"printedName": "[Swift.UInt8]",
"children": [
{
"kind": "TypeNominal",
"name": "UInt8",
"printedName": "Swift.UInt8",
"usr": "s:s5UInt8V"
}
],
"usr": "s:Sa"
}
],
"declKind": "Accessor",
"usr": "s:20unimoduleTyRecording15recordedPCMDataSays5UInt8VGvg",
"mangledName": "$s20unimoduleTyRecording15recordedPCMDataSays5UInt8VGvg",
"moduleName": "unimoduleTyRecording",
"implicit": true,
"accessorKind": "get"
},
{
"kind": "Accessor",
"name": "Set",
"printedName": "Set()",
"children": [
{
"kind": "TypeNominal",
"name": "Void",
"printedName": "()"
},
{
"kind": "TypeNominal",
"name": "Array",
"printedName": "[Swift.UInt8]",
"children": [
{
"kind": "TypeNominal",
"name": "UInt8",
"printedName": "Swift.UInt8",
"usr": "s:s5UInt8V"
}
],
"usr": "s:Sa"
}
],
"declKind": "Accessor",
"usr": "s:20unimoduleTyRecording15recordedPCMDataSays5UInt8VGvs",
"mangledName": "$s20unimoduleTyRecording15recordedPCMDataSays5UInt8VGvs",
"moduleName": "unimoduleTyRecording",
"implicit": true,
"accessorKind": "set"
},
{
"kind": "Accessor",
"name": "Modify",
"printedName": "Modify()",
"children": [
{
"kind": "TypeNominal",
"name": "Void",
"printedName": "()"
}
],
"declKind": "Accessor",
"usr": "s:20unimoduleTyRecording15recordedPCMDataSays5UInt8VGvM",
"mangledName": "$s20unimoduleTyRecording15recordedPCMDataSays5UInt8VGvM",
"moduleName": "unimoduleTyRecording",
"implicit": true,
"accessorKind": "_modify"
}
]
},
{
"kind": "Var",
"name": "targetSampleRate",
@@ -6260,31 +6040,17 @@
"length": 5,
"value": "false"
},
{
"filePath": "\/Users\/jlbank\/Desktop\/111\/unimoduleTyRecording\/src\/index.swift",
"kind": "IntegerLiteral",
"offset": 7751,
"length": 4,
"value": "4800"
},
{
"filePath": "\/Users\/jlbank\/Desktop\/111\/unimoduleTyRecording\/src\/index.swift",
"kind": "Array",
"offset": 7795,
"length": 2,
"value": "[]"
},
{
"filePath": "\/Users\/jlbank\/Desktop\/111\/unimoduleTyRecording\/src\/index.swift",
"kind": "FloatLiteral",
"offset": 7836,
"offset": 7736,
"length": 7,
"value": "16000.0"
},
{
"filePath": "\/Users\/jlbank\/Desktop\/111\/unimoduleTyRecording\/src\/index.swift",
"kind": "IntegerLiteral",
"offset": 7876,
"offset": 7776,
"length": 1,
"value": "1"
}
@@ -71,8 +71,6 @@ public var AudioErrors: [unimoduleTyRecording.AudioErrorCode : Swift.String]
public var isRecording: Swift.Bool
public var audioEngine: AVFAudio.AVAudioEngine?
public var inputNode: AVFAudio.AVAudioInputNode?
public var reuseInt32Array: DCloudUTSFoundation.Int32Array?
public var recordedPCMData: [Swift.UInt8]
public var targetSampleRate: Swift.Double
public var channels: Foundation.NSNumber
public var recordStartTime: Foundation.NSNumber?
@@ -71,8 +71,6 @@ public var AudioErrors: [unimoduleTyRecording.AudioErrorCode : Swift.String]
public var isRecording: Swift.Bool
public var audioEngine: AVFAudio.AVAudioEngine?
public var inputNode: AVFAudio.AVAudioInputNode?
public var reuseInt32Array: DCloudUTSFoundation.Int32Array?
public var recordedPCMData: [Swift.UInt8]
public var targetSampleRate: Swift.Double
public var channels: Foundation.NSNumber
public var recordStartTime: Foundation.NSNumber?
@@ -22,15 +22,15 @@
</data>
<key>Modules/unimoduleTyRecording.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo</key>
<data>
QbjcvbPxe2SMBqPdoCza55av/Tw=
TLOHHDzHkJ5T0ookGp0eUuKiAyU=
</data>
<key>Modules/unimoduleTyRecording.swiftmodule/arm64-apple-ios.abi.json</key>
<data>
Z7ggKmxb9JqzIhxdnP1xCbzzZ4k=
pbmeWUh86qZBo+NDNLQTkugcS1Q=
</data>
<key>Modules/unimoduleTyRecording.swiftmodule/arm64-apple-ios.private.swiftinterface</key>
<data>
LJpDEMNwHf014zr2KuiiwfkstBo=
3F+Z9ScbP7Joffio7FCaruBCwoM=
</data>
<key>Modules/unimoduleTyRecording.swiftmodule/arm64-apple-ios.swiftdoc</key>
<data>
@@ -38,11 +38,11 @@
</data>
<key>Modules/unimoduleTyRecording.swiftmodule/arm64-apple-ios.swiftinterface</key>
<data>
LJpDEMNwHf014zr2KuiiwfkstBo=
3F+Z9ScbP7Joffio7FCaruBCwoM=
</data>
<key>Modules/unimoduleTyRecording.swiftmodule/arm64-apple-ios.swiftmodule</key>
<data>
Pin0pLehK8375qWP03Epfm9w+Pk=
afsK4ngvO+GyKohHC+HTeaJlMQ4=
</data>
<key>config.json</key>
<data>
@@ -80,21 +80,21 @@
<dict>
<key>hash2</key>
<data>
947SepgiPHcaEuic0DLG2gwt/FS8rF716Trb8QOlqlM=
Eumt+b0A6MowWHNAl4LzHEqx8tqDes6Gkne6WMYV3no=
</data>
</dict>
<key>Modules/unimoduleTyRecording.swiftmodule/arm64-apple-ios.abi.json</key>
<dict>
<key>hash2</key>
<data>
B0HE4iiPSTwFN9Pz8MyiSw90PHoeoAGkINkAjKAquCE=
Eg/gzUqHUsddFo7fv6D4oO57364iyyHCDeuVA3FBOyY=
</data>
</dict>
<key>Modules/unimoduleTyRecording.swiftmodule/arm64-apple-ios.private.swiftinterface</key>
<dict>
<key>hash2</key>
<data>
+ZduByY3uAsmQpDhqBuZyAWRwjgdV2xjsJkZUbrlw5Q=
V39qYlvjQK7ofWRX95tTDt4mxPb23S3mMFWZi1LxJkA=
</data>
</dict>
<key>Modules/unimoduleTyRecording.swiftmodule/arm64-apple-ios.swiftdoc</key>
@@ -108,14 +108,14 @@
<dict>
<key>hash2</key>
<data>
+ZduByY3uAsmQpDhqBuZyAWRwjgdV2xjsJkZUbrlw5Q=
V39qYlvjQK7ofWRX95tTDt4mxPb23S3mMFWZi1LxJkA=
</data>
</dict>
<key>Modules/unimoduleTyRecording.swiftmodule/arm64-apple-ios.swiftmodule</key>
<dict>
<key>hash2</key>
<data>
FRUEjsQO4p4SSBQv/tNb1cDT4XQpnurMRxgSUr0nPBI=
vNu7jOeumiVckYl+2jb6jwGCh9aQAKf9KV4Vgrjrc6Y=
</data>
</dict>
<key>config.json</key>
+101 -96
View File
@@ -282,6 +282,7 @@
tempText.value = '';
allText.value = '';
ossKey.value = '';
pressTimer = setTimeout(() => {
if (!isRecording.value) {
console.log('定时器被取消还是进入了');
@@ -298,6 +299,100 @@
// 记录开始时间戳(毫秒)
recordStartTime.value = Date.now();
popupRef.value.open(); // 弹出录音界面
initWebSocket(wsUrl + '?summary=' + getToken())
.then((socketTask) => {
ws.value = socketTask;
ws.value.onMessage((res: { data: Uint8Array | ArrayBuffer }) => {
try {
const { msgType, body } = ProtocolCodec.unpack(res.data);
if (msgType === MessageType.TEXT_MESSAGE) {
tempText.value = '';
allText.value = allText.value + body;
} else if (msgType === MessageType.IDENTITY) {
console.log("错误消息", body);
const _errorBody = body as {code:number,msg:string };
const recordDurationMs = Date.now() - recordStartTime.value;
if(_errorBody?.code === 2) { // 认证错误,实际是登录失效
closeWS();
goto_login_fun();
stopAudioRecord(); // 关掉录音
setTimeout(() => closePopup, Math.max(700 - recordDurationMs, 0));
return;
} else if(_errorBody?.code === 1) {
if (!isRecording.value) {
ws.value = null;
wsStatus.value = false;
return;
}
console.log('开启语音');
wsStatus.value = true;
startRecordingTimer(true); // 启动超长定时器
} else if(_errorBody?.code === 3) { // 路数不够等问题
closeWS();
stopAudioRecord(); // 关掉录音
showErrorTip(_errorBody?.msg ?? '请稍后再试!');
setTimeout(() => closePopup, Math.max(700 - recordDurationMs, 0));
}
} else if (msgType === MessageType.TIP_MESSAGE) {
tempText.value = body as string;
} else if (msgType === MessageType.CONTROL_CMD) {
// 返回结束消息
const controlBody = body as ControlBody;
if (controlBody.type === ControlCode.SERVER_TO_FRONT_OVER) {
console.log(
'识别结束',
controlBody,
voice_to_text_status.value,
status.value,
voice_to_text_status.value
);
// 如果不等于init说明已经超时,被超时函数处理完了,这里即使返回也不做处理
if (
status.value === 'voice_to_text' &&
voice_to_text_status.value !== 'init'
)
return;
if (status.value === 'send_over') return;
// 时间太短,关掉的时候就处理了,这里不处理
const recordDurationMs = Date.now() - recordStartTime.value;
if (recordDurationMs <= props.minRecordDuration) return;
closeWS();
status.value = 'send_over'; // 设置成发送完成
if (voiceTimer) clearTimeout(voiceTimer);
// 设置识别结果
voice_to_text_status.value = controlBody?.txt === '' ? 'failed' : 'success';
// 取值出来
ossKey.value = controlBody?.ossKey || '';
if (typeof controlBody?.txt === 'string') {
allText.value = controlBody.txt.trim();
tempText.value = ''
}
const _isOutStatus =
workMode.value === 'text-only' && isOutStatus.value === '01'
? '03'
: isOutStatus.value;
// 只有模式为01的时候才发送出去
console.log('只有模式为01的时候才发送出去', controlBody);
if (_isOutStatus === '01') {
emit('submitVoice', {
ossKey: ossKey.value,
text: allText.value,
recordId: recordId.value
});
}
}
}
} catch (e) {
console.log('后端发来的信息有问题', e, res.data);
}
});
})
.catch(() => {
stopRecord('networkError');
console.log('网络出现问题');
});
startAudioRecord({
onFrame: (pcmData: any) => {
if (wsStatus.value && ws.value) {
@@ -310,8 +405,6 @@
// 发送完成后清空队列
voiceQueue = [];
}
console.log('再发送当前帧的音频数据', pcmData.length);
// 再发送当前帧的音频数据
ws.value.send({
data: ProtocolCodec.pack(MessageType.AUDIO_DATA, pcmData)
});
@@ -323,97 +416,6 @@
console.log('启动', res);
recordId.value = res.recordId ?? '';
console.log('WS连接成功', isRecording.value);
initWebSocket(wsUrl + '?summary=' + getToken())
.then((socketTask) => {
ws.value = socketTask;
ws.value.onMessage((res: { data: Uint8Array | ArrayBuffer }) => {
try {
const { msgType, body } = ProtocolCodec.unpack(res.data);
if (msgType === MessageType.TEXT_MESSAGE) {
tempText.value = '';
allText.value = allText.value + body;
} else if (msgType === MessageType.IDENTITY) {
console.log("错误消息", body);
const _errorBody = body as {code:number,msg:string };
if(_errorBody?.code === 2) { // 认证错误,实际是登录失效
closeWS();
goto_login_fun()
closePopup();
return;
} else if(_errorBody?.code === 1) {
if (!isRecording.value) {
ws.value = null;
wsStatus.value = false;
return;
}
console.log('开启语音');
wsStatus.value = true;
startRecordingTimer(true); // 启动超长定时器
} else if(_errorBody?.code === 3) { // 路数不够等问题
closeWS();
closePopup();
showErrorTip(_errorBody?.msg ?? '请稍后再试!');
}
} else if (msgType === MessageType.TIP_MESSAGE) {
tempText.value = body as string;
} else if (msgType === MessageType.CONTROL_CMD) {
// 返回结束消息
const controlBody = body as ControlBody;
if (controlBody.type === ControlCode.SERVER_TO_FRONT_OVER) {
console.log(
'识别结束',
controlBody,
voice_to_text_status.value,
status.value,
voice_to_text_status.value
);
// 如果不等于init说明已经超时,被超时函数处理完了,这里即使返回也不做处理
if (
status.value === 'voice_to_text' &&
voice_to_text_status.value !== 'init'
)
return;
if (status.value === 'send_over') return;
// 时间太短,关掉的时候就处理了,这里不处理
const recordDurationMs = Date.now() - recordStartTime.value;
if (recordDurationMs <= props.minRecordDuration) return;
closeWS();
status.value = 'send_over'; // 设置成发送完成
if (voiceTimer) clearTimeout(voiceTimer);
// 设置识别结果
voice_to_text_status.value = controlBody?.txt === '' ? 'failed' : 'success';
// 取值出来
ossKey.value = controlBody?.ossKey || '';
if (typeof controlBody?.txt === 'string') {
allText.value = controlBody.txt.trim();
tempText.value = ''
}
const _isOutStatus =
workMode.value === 'text-only' && isOutStatus.value === '01'
? '03'
: isOutStatus.value;
// 只有模式为01的时候才发送出去
console.log('只有模式为01的时候才发送出去', controlBody);
if (_isOutStatus === '01') {
emit('submitVoice', {
ossKey: ossKey.value,
text: allText.value,
recordId: recordId.value
});
}
}
}
} catch (e) {
console.log('后端发来的信息有问题', e, res.data);
}
});
})
.catch(() => {
stopRecord('networkError');
console.log('网络出现问题');
});
},
onStop: () => {
console.log('关闭');
@@ -425,7 +427,7 @@
}
}
});
}, 120);
}, 70);
};
// 结束录音
@@ -437,6 +439,7 @@
// 结束ws
const closeWS = () => {
startRecordingTimer(false);
console.log('ws.value', ws.value, wsStatus.value);
if (ws.value) {
ws.value.close({
code: 1000,
@@ -452,11 +455,14 @@
const stopRecord = async (errrStatus = '') => {
console.log('松手stopRecord', pressTimer, isRecording.value, status.value);
// 核心:计算录音总时长(毫秒转秒,保留1位小数)
const recordDurationMs = Date.now() - recordStartTime.value;
if (pressTimer) {
clearTimeout(pressTimer);
console.log('取消一个存在的定时器');
pressTimer = null;
isRecording.value = false;
setTimeout(() => closePopup, Math.max(700 - recordDurationMs, 0));
setTimeout(() => {
status.value = 'default';
}, 50);
@@ -468,8 +474,7 @@
closePopup();
return;
}
// 核心:计算录音总时长(毫秒转秒,保留1位小数)
const recordDurationMs = Date.now() - recordStartTime.value;
console.log('recordDurationMs', recordDurationMs);
// 拖动到转文字按钮上抬手或者仅文字模式的发送也强行算他转文字
const _isOutStatus = workMode.value === 'text-only' && isOutStatus.value === '01' ? '03' : isOutStatus.value;
@@ -103,8 +103,7 @@ export function startAudioRecord(options: StartAudioRecordOptions){
bufferSize= 2048, // 缓冲区大小,常用 1024/2048
format= inputFormat, // 音频格式
block=(buffer: AVAudioPCMBuffer, time: any) => {
const frameLen = buffer.frameLength as number;
const inputFrameLen = frameLen as Double;
const inputFrameLen = Double(buffer.frameLength);
const sampleRateRatio = targetSampleRate / inputFormat.sampleRate;
const outputFrameCounta = inputFrameLen * sampleRateRatio
const outputFrameCount = AVAudioFrameCount(outputFrameCounta);