So I have a music that starts playing in the AppDelegate (when the app is loaded basically), and I want to make it stop once I press a button on my settings scene that has its own ViewController class.
How can this be achieved? How can I access the variable I have on my appDelegate class that starts the music?
Here's the code for starting the music in AppDelegate:
var themeAudioURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("theme", ofType: "mp3")!)
var themePlayer = AVAudioPlayer()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
themePlayer = AVAudioPlayer(contentsOfURL: themeAudioURL, error: nil)
themePlayer.volume = 0.05
themePlayer.numberOfLoops = -1
themePlayer.play()
return true
}
You can pass player further to the next scene. You can do this in prepare for segue method. Alternatively you can get an app delegate in another view controller and cast it to your appdelegate implementation.
Related
This question already has answers here:
loading url from scheme not processing first time - appdelegate vs viewcontroller
(2 answers)
Closed 3 years ago.
I would like to know how to call a function from another function within AppDelegate. It would be better to call this function from ViewController but could not get it to work.
I have in my AppDelegate.m the following code:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
let geturl = url.host?.removingPercentEncoding;
UserDefaults.standard.set(geturl, forKey: "DeepLinkUrl")
return true
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
//I WANT CALL the upper function to set the URL IN HERE
return true
}
Since I don't know how to call the open url function from the ViewController.m I did this calling didFinishLaunchingWithOptions func from AppDelegate.m
My ViewController.m looks like:
#objc func appWillEnterForeground() {
print("app on foreground")
let appDelegate: AppDelegate? = UIApplication.shared.delegate as? AppDelegate
appDelegate?.application(UIApplication.shared, didFinishLaunchingWithOptions: nil)
//ACTUALLY I WANT TO CALL THE SET URL FUNCTION IN STEAD OF didFinishLaunchingWithOption BUT DON'T KNOW HOW. SO I FOUND THIS WHICH IS BEING CALLED
let user = UserDefaults.standard
if user.url(forKey: "DeepLinkUrl") != nil{
let str = user.value(forKey: "DeepLinkUrl") as! String
print(str)
}
}
Any ideas?
You don't call this method at all. It is called by the operating system when your application is launched. You are absolutely not supposed to ever call it yourself.
Same with the other method, which will be called by the operating system when your application is asked to open a URL. Which might be the URL of a file, or a URL with a scheme that you registered for.
Set a breakpoint on appDidFinishLaunching, then on your viewDidLoad method, start debugging to get some idea what is going on. You might also consider reading Apple's documentation.
I am having an issue where I am unable to access a function in my viewcontroller.swft file when lunching from a killed app in didFinishLaunchingWithOptions.
I am trying to access the function with viewController?.loadRequestnotificationwaiting(for: url as! String) from AppDelegate which I pass data to the viewcontroller where I can do some stuff. But when I place an alert in the function in the viewcontroller loadRequestnotificationwaiting. The data is not being passed.
Now I use this same method in other areas to pass data to the viewcontroller from the appdelegate and they work fine. It seems to not work when using it in didFinishLaunchingWithOptions
Is the viewcontroller not available yet when trying to access it from didFinishLaunchingWithOptions?
AppDelegate.swift
class AppDelegate : UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
weak var viewController : ViewController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().delegate = self
ConnectionManager.sharedInstance.observeReachability()
// Override point for customization after application launch.
FirebaseApp.configure()
registerForPushNotifications()
// opened from a push notification when the app is closed
if let userInfo = launchOptions?[.remoteNotification] as? [String : AnyObject] {
if let object = userInfo["aps"] {
let url = object["url"]
viewController?.loadRequestnotificationwaiting(for: url as! String)
}
}
return true
}
}
ViewController.swift
class ViewController: UIViewController, WKNavigationDelegate {
func loadRequestnotificationwaiting(for notification_url_wait : String) {
notification_url_final_wait = notification_url_wait
let url = URL(string: notification_url_final_wait!)
let URLrequest = URLRequest(url: url!)
self.webView.load(URLrequest)
}
}
You are relying on your AppDelegate's viewController property, but you are setting this property in your viewDidLoad method of your view controller; This is fine when a notification is received when your app is already running, since the viewController property is already set.
When a notification causes your application to be launched, the viewController property is not set and the function isn't called.
Assuming that the view controller you need is the initial view controller from your storyboard, you can get the root view controller from your app delegate's window property;
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().delegate = self
ConnectionManager.sharedInstance.observeReachability()
// Override point for customization after application launch.
FirebaseApp.configure()
registerForPushNotifications()
// opened from a push notification when the app is closed
if let userInfo = launchOptions?[.remoteNotification] as? [String : AnyObject] {
if let object = userInfo["aps"],
let url = object["url"] as? String,
let viewController = self.window?.rootViewController as? ViewController {
viewController.loadRequestnotificationwaiting(for: url)
}
}
return true
}
if your view controller is root, you can summon it by call UIApplication.shared.keyWindow!.rootViewController! or overwrite it with your viewController
you can raise a notification using -[NotificationCenter postNotificationName:object:userInfo:] and observe this notification name in View Controller
I need to loop a video in an Apple TV app, and I really would prefer to use TVJS so that we can update easily server side. However, when I loop the video, it shows the playback controls every time, and this is not ideal.
I see that AVPlayerViewController has a showsPlaybackControls bool that can be set to false, and is true by default, but the TVJS Player Class does not seem to have the same available to it.
What I am curious about is if there is a way that from the AppDelegate I can change that default from true to false so that the playbackControls never ever show? I have included my AppDelegate as well below. Thanks in advance!
import UIKit
import TVMLKit
import AVFoundation
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, TVApplicationControllerDelegate {
var window: UIWindow?
var appController: TVApplicationController?
static let TVBaseURL = "http://localhost:3000/"
static let TVBootURL = "\(AppDelegate.TVBaseURL)assets/tv.js"
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
window = UIWindow(frame: UIScreen.mainScreen().bounds)
let appControllerContext = TVApplicationControllerContext()
guard let javaScriptURL = NSURL(string: AppDelegate.TVBootURL) else {
fatalError("unable to create NSURL")
}
appControllerContext.javaScriptApplicationURL = javaScriptURL
appControllerContext.launchOptions["BASEURL"] = AppDelegate.TVBaseURL
appController = TVApplicationController(context: appControllerContext, window: window, delegate: self)
return true
}
}
I have an AVAudioPlayer set up in my AppDelegate to play on startup. It continues playing throughout the app, but when I try to stop or play the player in a different class, the app crashes with EXC_BAD_ACCESS on that line.
AppDelegate.swift
import AVFoundation
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var path = NSBundle.mainBundle().pathForResource("backgroundMusic", ofType: "wav")
var soundTrack = AVAudioPlayer()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
soundTrack = AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: path), error: nil)
soundTrack.numberOfLoops = -1
soundTrack.volume = 0.35
soundTrack.play()
return true
}
OtherClass.swift
func aFunction() {
let appDelegate = AppDelegate()
appDelegate.soundTrack.stop() //Here is where the app crashes. Same with .play()
}
Thanks for any help!
by doing AppDelegate() you are creating a new instance of app delegate; one which the variables haven't been initiated. You want to get the UiApplications shared delegate:
let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
I want my SpriteKit game not to interrupt background music that user listens (Music.app or radio app).
Everything goes fine until execution reaches this line:
sSharedShootSoundAction = [SKAction playSoundFileNamed:#"plane_shoot.aiff"
waitForCompletion:NO];
After this line background music stops. How to avoid this?
I have also encountered this problem myself. FYI my solutions are in swift so just translate this to Objective C if you are still using that.
For me my solution included two parts. First, I had to initialize my SoundAction SKAction within my didMoveToView function in my scene file. So your scene file should look something like this:
import SpriteKit
import GameKit
import AVFoundation
class GameScene: SKScene, SKPhysicsContactDelegate {
var sSharedShootSoundAction: SKAction = SKAction()
override func didMoveToView(view: SKView) {
/* Setup your scene here */
sSharedShootSoundAction = SKAction.playSoundFileNamed("plane_shoot.aiff", waitForCompletion: false)
}
}
Then in your AppDelegate file you need to place the following line of code in your application didFinishLaunchingWithOptions function. (DO NOT FORGET TO IMPORT AVFOUNDATION IN YOUR APPDELEGATE). So your app delegate method should like something like this:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
// INSERT THIS LINE BELOW.
AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient, error: nil)
return true
}
Hope this solves it for you as it did for me! Let me know if it doesn't.
Update for Swift 5, Xcode 11:
Put this into AppDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
// Below line will set all app sounds as ambient
try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.ambient)
return true
}