123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 |
- //
- // TSBandRingTool.swift
- // AIRingtone
- //
- // Created by 100Years on 2025/3/4.
- //
- import AVKit
- import AVFoundation
- class TSBandRingTool:NSObject {
- static var shared = TSBandRingTool()
- private var tutorialPlayer: AVPlayer?
- private var pictureController: AVPictureInPictureController?
- private lazy var playContentView = UIView(frame: UIScreen.main.bounds)
- private lazy var audioConvertTool = AudioTool()
-
- lazy var ringLoadingView: TSRingLoadingView = {
- let ringLoadingView = TSRingLoadingView(frame: CGRectMake(0, 0, k_ScreenWidth, k_ScreenHeight))
- return ringLoadingView
- }()
- weak var targetVC:UIViewController?
- // init(targetVC: UIViewController) {
- // self.targetVC = targetVC
- // }
-
- static func creatBandRingTool() -> TSBandRingTool{
- TSBandRingTool.shared = TSBandRingTool()
- return TSBandRingTool.shared
- }
-
- deinit {
- dePrint("TSBandRingTool deinit")
- }
- func checkGarageBandInstallation() -> Bool {
- // GarageBand 的 URL Scheme
- let garageBandScheme = "garageband://"
- if let url = URL(string: garageBandScheme), UIApplication.shared.canOpenURL(url) {
- print("GarageBand 已安装")
- return true
- } else {
- let ac = UIAlertController(title: nil,
- message: "GarageBand is not installed, you need to install it.", preferredStyle: .alert)
- ac.addAction(UIAlertAction(title: "Cancel", style: .cancel))
- ac.addAction(UIAlertAction(title: "Download", style: .default, handler: { _ in
- // GarageBand 在 App Store 的链接
- let garageBandAppStoreURL = URL(string: "https://apps.apple.com/app/id408709785")!
- if UIApplication.shared.canOpenURL(garageBandAppStoreURL) {
- UIApplication.shared.open(garageBandAppStoreURL, options: [:], completionHandler: nil)
- }
- }))
- targetVC?.present(ac, animated: true)
-
- return false
- }
- }
-
- func shareBandVC(vc:UIViewController,
- fileURL: URL,
- fileName:String?,
- completion: ((Bool) -> Void)? = nil) {
-
- if checkGarageBandInstallation() == false {
- completion?(false)
- return
- }
-
- if TSFileManagerTool.fileExists(at: fileURL) == false{
- completion?(false)
- return
- }
-
-
- self.targetVC = vc
- // if fileURLString.contains("http") {
-
- // if let window = WindowHelper.getKeyWindow() {
- // window.addSubview(ringLoadingView)
- // ringLoadingView.isRotating = true
- // }
-
- // _ = TSDownloadManager.downloadFile(urlString: fileURLString,missingEx: "mp3") {[weak self] url, error in
- // guard let self = self else { return }
- // ringLoadingView.removeFromSuperview()
-
- self.createBand(with: fileURL, fileName: fileName) { bandURL in
- if let url = bandURL {
- completion?(true)
- self.shareRing(fileUrl: url)
- }else{
- completion?(false)
- dePrint("Failed to set, please try another")
- }
- }
- // TSCommonTool.downloadAndCacheFile(from: fileURLString) { [weak self] path, error in
- // guard let self = self else { return }
- //// TSLoadingAnimation.hideLoading()
- // ringLoadingView.removeFromSuperview()
- // if let path = path,let url = URL(string: path) {
- // self.createBand(with: url, fileName: fileName) { bandURL in
- // if let url = bandURL {
- // completion?(true)
- // self.shareRing(fileUrl: url)
- // }else{
- // completion?(false)
- // dePrint("Failed to set, please try another")
- // }
- // }
- // }else{
- // dePrint("downloadAndCacheFile = \(error?.localizedDescription)")
- // completion?(false)
- // }
- // }
- // }else{
- // dePrint("ringtone no http")
- // completion?(false)
- // }
-
-
- }
-
- // 创建用于分享库乐队的band文件
- func createBand(with fileURL: URL?, fileName: String?,
- completion: ((URL?) -> Void)?) {
- let fileName = fileName ?? "Ringtone"
- guard let fileURL = fileURL,
- let bandPath = Self.bandPlacefolder,
- let directory = Self.ringDirectory else {
- completion?(nil)
- return
- }
-
- let bandURL = URL(fileURLWithPath: bandPath)
- let outputURL = URL(fileURLWithPath: directory).appendingPathComponent(fileName)
-
- audioConvertTool.convertToBand(from: fileURL, to: outputURL.path, bandFileURL: bandURL) { shareBandURL in
- completion?(shareBandURL)
- }
- }
-
- func shareRing(fileUrl: URL) {
- DispatchQueue.main.async {
- self.showTutorialVideo()
-
- let vc = UIActivityViewController(activityItems: [fileUrl], applicationActivities: nil)
- // 排除不需要的活动类型
- // vc.excludedActivityTypes = [
- // .postToFacebook,
- // .postToTwitter,
- // .postToWeibo,
- // .message,
- // .mail,
- // .print,
- // .copyToPasteboard,
- // .assignToContact,
- // .saveToCameraRoll,
- // .addToReadingList,
- // .postToFlickr,
- // .postToVimeo,
- // .postToTencentWeibo,
- // .airDrop,
- // .openInIBooks
- // ]
- self.targetVC?.present(vc, animated: true, completion: {
- self.tryStartPictureInPicture()
- })
-
- }
- }
-
- }
- extension TSBandRingTool : AVPlayerViewControllerDelegate, AVPictureInPictureControllerDelegate {
-
- func tryStartPictureInPicture() {
- guard let player = tutorialPlayer else {
- return
- }
- if player.status == .readyToPlay {
- self.pictureController?.startPictureInPicture()
- tutorialPlayer?.play()
- return
- }
- DispatchQueue.main.asyncAfter(deadline: .now()+0.1) {
- self.tryStartPictureInPicture()
- }
- }
-
- func showTutorialVideo() {
- guard let url = Bundle.main.url(forResource: "tutorial-ring", withExtension: "mp4") else {
- return
- }
- guard AVPictureInPictureController.isPictureInPictureSupported() else {
- return
- }
- do {
- try AVAudioSession.sharedInstance().setCategory(.playback, options: .mixWithOthers)
- } catch {
-
- }
-
- let playerItem = AVPlayerItem(asset: AVAsset(url: url))
- if tutorialPlayer == nil {
- tutorialPlayer = AVPlayer(playerItem: playerItem)
- } else {
- tutorialPlayer?.replaceCurrentItem(with: playerItem)
- }
- tutorialPlayer?.allowsExternalPlayback = true
-
- targetVC?.view.addSubview(playContentView)
-
- let layer = AVPlayerLayer(player: tutorialPlayer)
- layer.frame = CGRect(x: 0, y: 0, width: 1, height: 1)
- playContentView.layer.addSublayer(layer)
- let pictureVC = AVPictureInPictureController(playerLayer: layer)
- pictureVC?.delegate = self
- pictureController = pictureVC
-
- }
-
- func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
- playContentView.removeFromSuperview()
- }
-
- func playerViewControllerWillStartPictureInPicture(_ playerViewController: AVPlayerViewController) {
-
- }
-
- func playerViewControllerShouldAutomaticallyDismissAtPictureInPictureStart(_ playerViewController: AVPlayerViewController) -> Bool {
- return true
- }
-
- func playerViewController(_ playerViewController: AVPlayerViewController, restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void) {
- DispatchQueue.main.async {
- if playerViewController.presentingViewController == nil {
- self.targetVC?.present(playerViewController, animated: false)
- }
- completionHandler(true)
- }
- }
-
-
- }
- extension TSBandRingTool {
-
- static var bandPlacefolder: String? {
- guard let cacheDirectory = ringDirectory else {
- return nil
- }
- let path = NSString(string: cacheDirectory).appendingPathComponent("placeHolderBand.band")
-
- // 步骤1
- if !FileManager.default.fileExists(atPath: path),
- let localFile = Bundle.main.path(forResource: "placeholder.band", ofType: nil) {
- try? FileManager.default.copyItem(atPath: localFile, toPath: path)
- }
- return path
- }
-
- // 铃声文件夹
- static var ringDirectory: String? {
- guard let documentUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
- return nil
- }
- let ringDirectory = documentUrl.appendingPathComponent("ringDirectory")
-
- // 创建文件夹
- return FileManager.default.getFolder(at: ringDirectory)?.path
- }
- }
- extension FileManager {
- // 获取文件夹,如果不存在,则创建, 返回空则意味着创建失败
- func getFolder(at url: URL) -> URL? {
- guard !isFolderExists(at: url) else {
- return url
- }
- do {
- try createDirectory(at: url, withIntermediateDirectories: true, attributes: nil)
- return url
- } catch {
- return nil
- }
- }
-
- func isFolderExists(at url: URL) -> Bool {
- var isDirectory: ObjCBool = false
- if fileExists(atPath: url.path, isDirectory: &isDirectory) && isDirectory.boolValue == true {
- return true // 文件夹已存在
- } else {
- return false // 文件夹不存在或者路径错误
- }
- }
- }
|