XCode 发起视频 和 收到视频通话邀请实现双语功能 中文和俄语

目录

[🚀 一键生成 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

🎉 完成效果

运行后你会得到:

  • ✔ 视频界面(摄像头)

  • ✔ 中文语音识别

  • ✔ 中 → 俄字幕

  • ✔ 发起 / 接听流程

相关推荐
大龄秃头程序员12 小时前
Sendable 不是“能跑就行”:Swift Concurrency 下的实战踩坑与架构落地指南
swift
大熊猫侯佩1 天前
WWDC26 全新 SwiftData 的 .codable 宏选项:它不是泛型专用胶水
数据库·swift·apple
大龄秃头程序员1 天前
Swift 并发实战:从 Task 到 Actor 重入性,我掉进了“逻辑不一致”的坑
swift
LinXunFeng1 天前
给 Flutter 插件加上 Swift Package Manager 支持
flutter·swift
大龄秃头程序员2 天前
Swift 面试反直觉:Property Wrapper 真的拿不到宿主 self 吗?
swift
FeliksLv2 天前
从 +load 到 Swift Macros:自动注册的演进与实践
ios·objective-c·swift
语歌2 天前
AI 语言学习系统的工程边界:为什么 LLM 不该负责复习排期
人工智能·swift
2501_916008893 天前
iOS应用开发工具全面解析:如何选择与优化开发效率
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
大龄秃头程序员3 天前
Swift 属性包装器进阶:从“语法糖”到“并发安全”的 5 个深坑
swift