目录
[🚀 一键生成 Xcode Demo 工程(完整版)](#🚀 一键生成 Xcode Demo 工程(完整版))
[✅ 第一步:创建工程(用 Xcode CLI)](#✅ 第一步:创建工程(用 Xcode CLI))
[✅ 第二步:创建源码目录](#✅ 第二步:创建源码目录)
[✅ 第三步:创建核心文件](#✅ 第三步:创建核心文件)
[🔹 main.swift(入口)](#🔹 main.swift(入口))
[🔹 ViewController.swift](#🔹 ViewController.swift)
[🔹 CallViewController.swift](#🔹 CallViewController.swift)
[🔹 SpeechManager.swift](#🔹 SpeechManager.swift)
[🔹 TranslateManager.swift](#🔹 TranslateManager.swift)
[🔹 CameraManager.swift](#🔹 CameraManager.swift)
[✅ 第四步:直接生成 Xcode 工程](#✅ 第四步:直接生成 Xcode 工程)
[⚠️ 第五步(必须做)](#⚠️ 第五步(必须做))
[🎉 完成效果](#🎉 完成效果)
🚀 一键生成 Xcode Demo 工程(完整版)
✅ 第一步:创建工程(用 Xcode CLI)
cd ~/Desktop
mkdir VideoCallDemo
cd VideoCallDemo
swift package init --type executable
👉 然后执行:
open Package.swift
把它改成👇(关键)
// swift-tools-version:5.9
import PackageDescription
let package = Package(
name: "VideoCallDemo",
platforms: [.iOS(.v15)],
products: [
.iOSApplication(
name: "VideoCallDemo",
targets: ["AppModule"],
bundleIdentifier: "com.demo.videocall",
teamIdentifier: "",
displayVersion: "1.0",
bundleVersion: "1",
iconAssetName: "AppIcon",
accentColorAssetName: "AccentColor"
)
],
targets: [
.executableTarget(
name: "AppModule",
path: "Sources"
)
]
)
✅ 第二步:创建源码目录
rm -rf Sources/*
mkdir Sources/AppModule
cd Sources/AppModule
✅ 第三步:创建核心文件
🔹 main.swift(入口)
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = ViewController()
window?.makeKeyAndVisible()
return true
}
}
🔹 ViewController.swift
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
let callBtn = UIButton(frame: CGRect(x: 80, y: 200, width: 240, height: 50))
callBtn.setTitle("发起视频通话", for: .normal)
callBtn.backgroundColor = .systemBlue
callBtn.addTarget(self, action: #selector(startCall), for: .touchUpInside)
let receiveBtn = UIButton(frame: CGRect(x: 80, y: 300, width: 240, height: 50))
receiveBtn.setTitle("模拟来电", for: .normal)
receiveBtn.backgroundColor = .systemGreen
receiveBtn.addTarget(self, action: #selector(receiveCall), for: .touchUpInside)
view.addSubview(callBtn)
view.addSubview(receiveBtn)
}
@objc func startCall() {
present(CallViewController(), animated: true)
}
@objc func receiveCall() {
let alert = UIAlertController(title: "来电", message: "是否接听?", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "接听", style: .default) { _ in
self.present(CallViewController(), animated: true)
})
alert.addAction(UIAlertAction(title: "拒绝", style: .cancel))
present(alert, animated: true)
}
}
🔹 CallViewController.swift
import UIKit
import AVFoundation
import Speech
class CallViewController: UIViewController {
let cameraView = UIView()
let subtitleLabel = UILabel()
let speech = SpeechManager()
let translator = TranslateManager()
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
startSpeech()
CameraManager().startPreview(in: cameraView)
}
func setupUI() {
view.backgroundColor = .black
cameraView.frame = view.bounds
view.addSubview(cameraView)
subtitleLabel.frame = CGRect(x: 20, y: view.frame.height - 200, width: view.frame.width - 40, height: 80)
subtitleLabel.textColor = .white
subtitleLabel.numberOfLines = 0
view.addSubview(subtitleLabel)
let hangup = UIButton(frame: CGRect(x: view.center.x - 30, y: view.frame.height - 80, width: 60, height: 60))
hangup.backgroundColor = .red
hangup.layer.cornerRadius = 30
hangup.setTitle("挂", for: .normal)
hangup.addTarget(self, action: #selector(close), for: .touchUpInside)
view.addSubview(hangup)
}
@objc func close() {
dismiss(animated: true)
}
func startSpeech() {
speech.start { text in
DispatchQueue.main.async {
self.subtitleLabel.text = text
}
self.translator.translateToRussian(text: text) { ru in
DispatchQueue.main.async {
self.subtitleLabel.text = "\(text)\n\(ru)"
}
}
}
}
}
🔹 SpeechManager.swift
import Speech
import AVFoundation
class SpeechManager {
let recognizer = SFSpeechRecognizer(locale: Locale(identifier: "zh-CN"))
let engine = AVAudioEngine()
func start(callback: @escaping (String)->Void) {
let request = SFSpeechAudioBufferRecognitionRequest()
recognizer?.recognitionTask(with: request) { result, _ in
if let text = result?.bestTranscription.formattedString {
callback(text)
}
}
let node = engine.inputNode
node.installTap(onBus: 0, bufferSize: 1024, format: node.outputFormat(forBus: 0)) {
buffer, _ in
request.append(buffer)
}
try? engine.start()
}
}
🔹 TranslateManager.swift
class TranslateManager {
func translateToRussian(text: String, completion: @escaping (String)->Void) {
DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) {
completion("(俄语)\(text)")
}
}
}
🔹 CameraManager.swift
import AVFoundation
import UIKit
class CameraManager {
func startPreview(in view: UIView) {
let session = AVCaptureSession()
guard let device = AVCaptureDevice.default(for: .video),
let input = try? AVCaptureDeviceInput(device: device)
else { return }
session.addInput(input)
let preview = AVCaptureVideoPreviewLayer(session: session)
preview.frame = view.bounds
preview.videoGravity = .resizeAspectFill
view.layer.addSublayer(preview)
session.startRunning()
}
}
✅ 第四步:直接生成 Xcode 工程
swift package generate-xcodeproj
open VideoCallDemo.xcodeproj
⚠️ 第五步(必须做)
在 Xcode → Info.plist 添加:
Privacy - Camera Usage Description
Privacy - Microphone Usage Description
Privacy - Speech Recognition Usage Description
🎉 完成效果
运行后你会得到:
-
✔ 视频界面(摄像头)
-
✔ 中文语音识别
-
✔ 中 → 俄字幕
-
✔ 发起 / 接听流程