Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import UIKit
- import Flutter
- import AVFoundation
- import MediaPlayer
- import flutter_downloader
- @available(iOS 11, *)
- @UIApplicationMain
- @objc class AppDelegate: FlutterAppDelegate {
- var player: AVPlayer?
- var volume: Float = 1
- var muted: Bool = false
- var lastTrack: String = ""
- var channel: FlutterMethodChannel!
- override func application(
- _ application: UIApplication,
- didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
- ) -> Bool {
- GeneratedPluginRegistrant.register(with: self)
- FlutterDownloaderPlugin.setPluginRegistrantCallback(registerPlugins)
- let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
- channel = FlutterMethodChannel(name: "lighthouse_audio_stream", binaryMessenger: controller.binaryMessenger)
- NotificationCenter.default.addObserver(
- self,
- selector: #selector(playerItemDidReachEnd),
- name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
- object: nil
- )
- channel.setMethodCallHandler({
- (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
- switch(call.method) {
- case "play":
- if let args = call.arguments as? Dictionary<String, String> {
- let url = args["url"] ?? ""
- let title = args["title"] ?? ""
- let description = args["description"] ?? ""
- let image = args["image"] ?? ""
- if (url.isEmpty) {
- result(FlutterError.init(code: "no url passed", message: "nill", details: "Nill"))
- } else {
- do {
- let isSameTrack = self.lastTrack == url;
- if !isSameTrack {
- self.lastTrack = url;
- }
- try self.play(url: url, isSameTrack: isSameTrack, title: title, description: description, image: image)
- UIApplication.shared.beginReceivingRemoteControlEvents()
- result(0)
- } catch {
- result(0)
- }
- }
- } else {
- result(FlutterError.init(code: "no url passed", message: "nill", details: "Nill"))
- }
- result(0)
- return
- case "disk":
- if let args = call.arguments as? Dictionary<String, Any>,
- let path = args["path"] as? String {
- result(self.diskUsage(path: path))
- } else {
- result(FlutterError.init(code: "no url passed", message: "nill", details: "Nill"))
- }
- result(0)
- return
- case "seek":
- if let args = call.arguments as? Dictionary<String, Any>,
- let pos = args["pos"] as? Double {
- self.seek(pos: pos / 1000)
- result(nil)
- } else {
- result(FlutterError.init(code: "no position passed", message: "nill", details: "Nill"))
- }
- result(0)
- return
- case "pause":
- self.pause()
- result(nil)
- return
- case "stop":
- self.stop()
- result(nil)
- return
- case "mute":
- self.mute()
- result(nil)
- return
- case "forward":
- self.seekTo(forward: true)
- return
- case "rewind":
- self.seekTo(forward: false)
- return
- case "currentPos":
- let position = self.currentPos();
- result(position)
- return
- case "rate":
- self.rate()
- result(nil)
- return
- default:
- result(FlutterMethodNotImplemented)
- }
- })
- return super.application(application, didFinishLaunchingWithOptions: launchOptions)
- }
- @objc func playerItemDidReachEnd(notification: NSNotification) {
- channel.invokeMethod("stop", arguments: 0)
- }
- override func remoteControlReceived(with event: UIEvent?) {
- guard let event = event else {
- return
- }
- guard event.type == UIEvent.EventType.remoteControl else {
- return
- }
- switch event.subtype {
- case UIEventSubtype.remoteControlPlay:
- player?.play()
- channel.invokeMethod("playing", arguments: 0)
- case UIEventSubtype.remoteControlPause:
- player?.pause()
- channel.invokeMethod("pause", arguments: nil)
- case UIEventSubtype.remoteControlTogglePlayPause:
- print("received toggle\n")
- case UIEventSubtype.remoteControlNextTrack:
- channel.invokeMethod("next", arguments: nil)
- case UIEventSubtype.remoteControlPreviousTrack:
- channel.invokeMethod("prev", arguments: nil)
- default:
- print("received \(event.subtype) which we did not process\n")
- }
- }
- private func play(url: String, isSameTrack: Bool, title: String, description: String, image: String) throws {
- let location: URL? = url.hasPrefix("http") ? URL(string: url) : NSURL.fileURL(withPath: url);
- if let audioUrl = location {
- if (player == nil || !isSameTrack) {
- player = AVPlayer(url: audioUrl)
- player?.automaticallyWaitsToMinimizeStalling = false;
- setupNowPlayingInfo(title: title, artist: description, image: image)
- }
- player?.play()
- } else {
- throw PlayerErrors.InvalidUrl
- }
- }
- private func seekTo(forward: Bool) {
- if player != nil {
- let currentPos = CMTimeGetSeconds(player?.currentTime() ?? CMTime(seconds: 0.0, preferredTimescale: 1))
- let goto = forward ? (currentPos + 10.0) : (currentPos - 10.0)
- player?.seek(to: CMTime(seconds: goto, preferredTimescale: 1))
- }
- }
- private func seek(pos: Double) {
- if player != nil {
- player?.seek(to: CMTime(seconds: pos, preferredTimescale: 1))
- }
- }
- private func pause() {
- if player != nil {
- player?.pause()
- }
- }
- private func stop() {
- if player != nil {
- player?.pause()
- player = nil
- }
- }
- private func rate() {
- if let url = URL(string: "itms-apps://apple.com/app/com.thelighthouseapp.app") {
- UIApplication.shared.open(url)
- }
- }
- private func currentPos() -> [String: Double] {
- if player != nil {
- var duration = CMTimeGetSeconds(player?.currentItem?.duration ?? CMTime(seconds: 1.0, preferredTimescale: 1))
- if (duration.isNaN || duration < 1) {
- duration = 1
- }
- let currentTime = CMTimeGetSeconds(player?.currentTime() ?? CMTime(seconds: 0.0, preferredTimescale: 1));
- MPNowPlayingInfoCenter.default().nowPlayingInfo?[MPNowPlayingInfoPropertyElapsedPlaybackTime] = (currentTime / duration) * 100
- return ["duration": duration * 1000.0, "currentPos": currentTime * 1000.0]
- }
- return ["duration": 1.0, "currentPos": 0.0]
- }
- private func mute() {
- if player != nil {
- if muted {
- player?.volume = volume
- muted = false
- } else {
- volume = player?.volume ?? 1.0
- player?.volume = 0.0
- muted = true
- }
- }
- }
- @available(iOS 11, *)
- private func diskUsage(path: String) -> [String: Int] {
- let dirURL = URL(fileURLWithPath: path)
- do {
- let values = try dirURL.resourceValues(forKeys: [.volumeAvailableCapacityKey, .fileSizeKey, .isDirectoryKey])
- if (values.isDirectory ?? false) {
- let diskSize = values.volumeAvailableCapacity ?? 0
- var usedSpace = 0
- (FileManager.default.enumerator(at: dirURL, includingPropertiesForKeys: nil)?.allObjects as? [URL])?.lazy.forEach {
- usedSpace += (try? $0.resourceValues(forKeys: [.totalFileAllocatedSizeKey]))?.totalFileAllocatedSize ?? 0
- }
- return ["totalSpace": diskSize, "usedSpace": usedSpace]
- } else {
- return ["totalSpace": 1, "usedSpace": 0]
- }
- } catch {
- return ["totalSpace": 1, "usedSpace": 0]
- }
- }
- func setupNowPlayingInfo(title: String, artist: String, image: String) {
- var nowPlayingInfo = [String: Any]()
- nowPlayingInfo[MPMediaItemPropertyTitle] = title
- nowPlayingInfo[MPMediaItemPropertyArtist] = artist
- MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
- }
- fileprivate func setupAudioSession() {
- do {
- try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, mode: .default)
- try AVAudioSession.sharedInstance().setActive(true)
- } catch let sessionErr {
- print("Failed to activate session:", sessionErr)
- }
- }
- deinit {
- NotificationCenter.default.removeObserver(self)
- }
- }
- enum PlayerErrors: Error {
- case InvalidUrl
- func val() -> String {
- switch self {
- case .InvalidUrl:
- return "Cannot play file from this url"
- }
- }
- }
- private func registerPlugins(registry: FlutterPluginRegistry) {
- if (!registry.hasPlugin("FlutterDownloaderPlugin")) {
- FlutterDownloaderPlugin.register(with: registry.registrar(forPlugin: "FlutterDownloaderPlugin"))
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement