I am trying to add a interstitial ad in a Swift SpriteKit game and most of the problems/soultions I see are related to the banner view and not the interstitial display of the admob ads.
What I did was adding all the frameworks and the sample code from google like described here Adding interstitial ads to your project into my GamveViewController.swift
import UIKit
import GoogleMobileAds
class ViewController: UIViewController {
var interstitial: GADInterstitial!
override func viewDidLoad() {
super.viewDidLoad()
interstitial = GADInterstitial(adUnitID: "ca-app-pub-3940256099942544/4411468910")
let request = GADRequest()
// Requests test ads on test devices.
request.testDevices = ["2077ef9a63d2b398840261c8221a0c9b"]
interstitial.loadRequest(request)
}
}
Then I want to call the function to display the ad in my GameScene.swift and this leads to an error and I dont know why
if (self.interstitialAd.isReady) {
self.interstitialAd.presentFromRootViewController(self)
}
The error codes I get are:
1. "use of undeclared type "GADInerstittial"
2."GameScene has no member interstitial
It seems I need to connect my GameViewController and the Game Scene, but I do not know how. Anyone with a helping hand?
You cannot just present the ad in a gameScene, you need a viewController.
The easiest way is to put the code from GameScene into your ViewController.
So move/or create a func in ViewController like so
func showInterAd() {
/// code to present inter ad
}
Than you can use something like NSNotificationCenter to forward the message from GameScene to the ViewController.
Still in your ViewController add an observer in viewDidLoad
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(showInterAd), name: "ShowAd", object: nil)
Than in your GameScene when you want to show the ad post the notification.
NSNotificationCenter.defaultCenter().postNotificationName("ShowAd", object: nil)
Alternatively I have a helper on gitHub if you want a cleaner and more reusable solution
https://github.com/crashoverride777/Swift-iAds-AdMob-CustomAds-Helper
Related
I am building an iOS app using the new language Swift. Now it is an HTML5 app, that displays HTML content using the UIWebView. The app has local notifications, and what i want to do is trigger a specific javascript method in the UIWebView when the app enters foreground by clicking (touching) the local notification.
I have had a look at this question, but it does not seem to solve my problem. I have also come across this question which tells me about using UIApplicationState, which is good as that would help me know the the app enters foreground from a notification. But when the app resumes and how do i invoke a method in the viewController of the view that gets displayed when the app resumes?
What i would like to do is get an instance of my ViewController and set a property in it to true. Something as follows
class FirstViewController: UIViewController,UIWebViewDelegate {
var execute:Bool = false;
#IBOutlet var tasksView: UIWebView!
}
And in my AppDelegate i have the method
func applicationWillEnterForeground(application: UIApplication!) {
let viewController = self.window!.rootViewController;
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
var setViewController = mainStoryboard.instantiateViewControllerWithIdentifier("FirstView") as FirstViewController
setViewController.execute = true;
}
so what i would like to do is when the app enters foreground again, i want to look at the execute variable and run the method as follows,
if execute{
tasksView.stringByEvaluatingJavaScriptFromString("document.getElementById('sample').click()");
}
Where should i put the code for the logic to trigger the javascript from the webview? would it be on viewDidLoad method, or one of the webView delegate methods? i have tried to put that code in the viewDidLoad method but the value of the boolean execute is set to its initial value and not the value set in the delegate when the app enters foreground.
If I want a view controller to be notified when the app is brought back to the foreground, I might just register for the UIApplication.willEnterForegroundNotification notification (bypassing the app delegate method entirely):
class ViewController: UIViewController {
private var observer: NSObjectProtocol?
override func viewDidLoad() {
super.viewDidLoad()
observer = NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main) { [unowned self] notification in
// do whatever you want when the app is brought back to the foreground
}
}
deinit {
if let observer = observer {
NotificationCenter.default.removeObserver(observer)
}
}
}
Note, in the completion closure, I include [unowned self] to avoid strong reference cycle that prevents the view controller from being deallocated if you happen to reference self inside the block (which you presumably will need to do if you're going to be updating a class variable or do practically anything interesting).
Also note that I remove the observer even though a casual reading of the removeObserver documentation might lead one to conclude is unnecessary:
If your app targets iOS 9.0 and later or macOS 10.11 and later, you don't need to unregister an observer in its dealloc method.
But, when using this block-based rendition, you really do need to remove the notification center observer. As the documentation for addObserver(forName:object:queue:using:) says:
To unregister observations, you pass the object returned by this method to removeObserver(_:). You must invoke removeObserver(_:) or removeObserver(_:name:object:) before any object specified by addObserver(forName:object:queue:using:) is deallocated.
I like to use the Publisher initializer of NotificationCenter. Using that you can subscribe to any NSNotification using Combine.
import UIKit
import Combine
class MyFunkyViewController: UIViewController {
/// The cancel bag containing all the subscriptions.
private var cancelBag: Set<AnyCancellable> = []
override func viewDidLoad() {
super.viewDidLoad()
addSubscribers()
}
/// Adds all the subscribers.
private func addSubscribers() {
NotificationCenter
.Publisher(center: .default,
name: UIApplication.willEnterForegroundNotification)
.sink { [weak self] _ in
self?.doSomething()
}
.store(in: &cancelBag)
}
/// Called when entering foreground.
private func doSomething() {
print("Hello foreground!")
}
}
Add Below Code in ViewController
override func viewDidLoad() {
super.viewDidLoad()
let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self, selector:#selector(appMovedToForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
}
#objc func appMovedToForeground() {
print("App moved to foreground!")
}
In Swift 3, it replaces and generates the following.
override func viewDidLoad() {
super.viewDidLoad()
foregroundNotification = NotificationCenter.default.addObserver(forName:
NSNotification.Name.UIApplicationWillEnterForeground, object: nil, queue: OperationQueue.main) {
[unowned self] notification in
// do whatever you want when the app is brought back to the foreground
}
I've successfully integrated Google Sign-In into my iOS app in my AppDelegate.swift file, and can successfully detect a successful sign-in (by printing "success" out onto the console). The issue is that after a successful sign-in, I'm back at the Google Sign-In page when I want to be in the next screen of the app.
The AppDelegate.swift file did not recognize the performSegue function, as it is a function of the UIViewController class (please correct me if I'm wrong). To get around this, I created a global variable in the ViewController file such that the segue would be performed whenever this value would be changed:
AppDelegate.swift:
var userSignedInGlobal = "n/a"
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate {
// A bunch of code that implements the Google Sign in ...
print("Successfully logged into Google.", user)
userSignedInGlobal = "success"
}
And then my InitialViewController.swift file:
class InitialViewController: UIViewController, GIDSignInUIDelegate {
var userSignedIn = userSignedInGlobal {
didSet {
performSegue(withIdentifier: "segueOne", sender: self)
}
}
// A bunch of irrelevant code.
}
This did not work, and the reason I think this didn't work is that userSignedInGlobal in the InitialViewController.swift file is being passed by reference - so even when its value changes, the value of userSignedIn does not change (again, please do correct me if I'm wrong).
To get around this, I changed my InitialViewController.swift file as follows:
var userSignedIn = userSignedInGlobal {
didSet {
doSegue()
}
}
class InitialViewController: UIViewController, GIDSignInUIDelegate {
func doSegue() {
performSegue(withIdentifier: "segueOne", sender: self)
}
// A bunch of irrelevant code.
}
This gave me an error in the third line: "Use of unresolved identifier 'doSegue()' "
I do not know how to go about performing the segue when the sign in is successful. Any help will be greatly appreciated, thanks in advance.
There are a few problems here:
Global Variables in App Delegate
There are numerous answers demonstrating how to store a global variable in your AppDelegate and then subsequently reference that variable in your view controllers, e.g. getting a reference to app delegate
Perform Segue only from Storyboard based controllers
You won't be able to use performSegue unless your current View Controller was loaded from a StoryBoard (see performSegue). This probably is not the case with whatever Google view you are loading from your AppDelegate.
Are you doing the login in the right place?
You might want to reconsider the division of duties between your AppDelegate and your initial view controller. Perhaps you are trying to do too much in the AppDelegate. Perhaps you should move some of this code (showing the Google form) to your initial VC and then either segue or reset your Navigation Controller based on the result.
Hope this helps.
I'm dealing with the Admob interstitials and in particular I'm trying to display an interstitial when a particular ViewController of my app loads. I used the code provided by the official Admob Interstitial guide but it doesn't work :https://developers.google.com/admob/ios/interstitial?hl=it. I also followed this video here :https://youtu.be/ahmQQ3OeY0Y?t=787 (minute 13.04 stop the video). If you look at the code is the same as in the guide. My objective is to display the ad when the RequestViewController appears so I try to present the ad in the viewDidAppear function. Anyway it doesn't work, the console displays this error:
To get test ads on this device, call: request.testDevices =
#[ kGADSimulatorID ]
AppDelegate.swift
import UIKit
import UserNotifications
import GoogleMobileAds
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate,GADInterstitialDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
GADMobileAds.configure(withApplicationID: "ca-app-pub-*******")
}
}
This is the ViewController where I present the ad:
RequestviewController.swift
class RequestViewController: UIViewController {
var myInterstitial : GADInterstitial?
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
//display ad
myInterstitial = createAndLoadInterstitial()
if (myInterstitial?.isReady)!{
print("\n\n\n\n\nReady")
myInterstitial?.present(fromRootViewController: self)
}else { print("\n\n\n\nAd wasn't ready") }
}
func createAndLoadInterstitial()->GADInterstitial {
let interstitial = GADInterstitial(adUnitID: "ca-app-pub-3940256099942544/4411468910") //test Ad unit id
interstitial.delegate = self
interstitial.load(GADRequest())
return interstitial
}
func interstitialDidReceiveAd(ad: GADInterstitial!) {
print("interstitialDidReceiveAd")
}
func interstitial(ad: GADInterstitial!, didFailToReceiveAdWithError error: GADRequestError!) {
print(error.localizedDescription)
}
func interstitialDidDismissScreen(ad: GADInterstitial!) {
print("\n\n\n\n\n\ninterstitialDidDismissScreen")
myInterstitial = createAndLoadInterstitial()
}
you need to write it like,
appDelegate.createAndLoadInterstitial()
in place of,
appDelegate.myInterstitial?.present(fromRootViewController: self)
It looks like the root problem is this section of RequestViewController:
myInterstitial = createAndLoadInterstitial()
if (myInterstitial?.isReady)!{
print("\n\n\n\n\nReady")
myInterstitial?.present(fromRootViewController: self)
}else { print("\n\n\n\nAd wasn't ready") }
Interstitials are loaded asynchronously, which means the call to load() will return before the ad is loaded and ready to display. If your app is calling load() in createAndLoadInterstitial and then checking isReady immediately afterwards, there's no time for the ad to actually load, and isReady will always be false.
A good way to deal with this could be to create the interstitial in your first view controller, and then show it before transitioning to RequestViewController. That would give the ad time to load, and would still display it during the same transition.
FWIW, transition time between ViewControllers is a great place in the flow of your app to use an interstitial, so well done there.
Also, the line:
To get test ads on this device, call: request.testDevices = #[ kGADSimulatorID ]
isn't an error. The Android and iOS SDKs always print that to the log so publishers will know how to get test ads for a particular device or emulator. If you were running on a hardware device instead of the iOS simulator, you'd see a unique identifier for the device in that line, which you could then use in your code to get test ads.
I'm trying to create a MacOS app that plays audio or video files. I've followed the simple instructions on Apple's website here
But I want to use the File > Open menu items to bring up an NSOpenPanel, and pass that to the View Controller.
So presumably, the Open action should be in the AppDelegate, as the ViewController window might not be open.
And then pass the filename to a new instance of the ViewController window.
Is that right? If so, how do I "call" the View from AppDelegate?
Here's the AppDelegate:
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBAction func browseFile(sender: AnyObject) {
let dialog = NSOpenPanel();
if (dialog.runModal() == NSModalResponseOK) {
let result = dialog.url // Pathname of the file
if (result != nil) {
// Pass the filepath to the window view thing.
} else {
// User clicked on "Cancel"
return
}
}
}
and here's the ViewController:
class ViewController: NSViewController {
#IBOutlet weak var playerView: AVPlayerView!
override func viewDidLoad() {
super.viewDidLoad()
// Get the URL somehow
let player = AVPlayer(url: url)
playerView.player = player
}
There are some details not disclosed in your question, but I believe I can provide the proper answer still.
You can call NSOpenPanel from AppDelegate, nothing wrong with that. Just note that user may cancel the dialog and how to handle that situation.
Considering the view the best thing is to create WindowController that is connected to the ViewController (it is like that by default) in the Storyboard, then access it from the code using NSStoryBoard.instantiateController(withIdentifier:), and then use its window property with something like window.makeKeyAndOrderFront(self) . If you have NSWindow or NSWindowController class in your code then you should initialize the class in the code and again make window key and front.
I've made a game using SpriteBuilder and it's written in Swift. I'd like to add advertisements before I ship an update to the App Store. Can someone please help me with how to do this?
To add iAd to your game, you need to add the iAd framework to your app (via Build Phases) and add the import statement import iAd in the class that handles your iAd implementation.
The simplest iAd ad to add to your Swift game is a banner ad:
override func viewDidLoad() {
super.viewDidLoad()
self.canDisplayBannerAds = true
}
Make sure to import iAd and add the AdBannerViewDelegate protocol to your class declaration:
import iAd
class MasterViewController: UITableViewController, NSFetchedResultsControllerDelegate,ADBannerViewDelegate
Then you need to create the actual banner view, set the delegate (in ViewDidLoad) and add two delegate methods, so that you know when to add/remove the advertisement banner from the view:
bannerViewDidLoadAd:
bannerView:didFailToReceiveAdWithError:
It's fairly easy.
1) Import the iAd framework >Build Phases> Link Binary With Libraries> find iAd
2) drag an iAd BannerView from the object library
3) Make an outlet connecting the iAd BannerView to your VC file
4) Add the delegate to your VC class
import iAd
class ViewController: UIViewController, ADBannerViewDelegate{
#IBOutlet var adBannerView: ADBannerView?
override func viewDidLoad(){
self.canDisplayBannerAds = true
self.ADBannerView?.delegate = self
self.ADBannerView.hidden = true
}
func bannerViewWillLoadAd(banner: AdBannerView!){ // any addition set up you want
}
func bannerViewDidLoadAd(banner: ADBannerView!){
self.ADBannerView?.hidden = false
}
func bannerViewActionDidFinish(banner: ADBannerView!){// any addition set up you want
}
func bannerViewActionShouldBegin(banner: ADBannerView!, willLeaveApplication willLeave: Boll) -> Bool {
return true
}
func bannerView(banner: ADBannerView!, didFailToReceiveAdWithError error: NSError!){
self.adBannerView?.hidden = false
}
}
Of course you'll have to adjust to display when ever and where you wan it.