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.
Related
I am trying to do the (seemingly) simple task of integrating Native AdMob ads into my iOS app running on Swift. Let me first show you my storyboards and code for integration and then we'll move on to things I've tried to fix it.
Set-Up: Storyboards and Code
In my App Delegate, I configure Firebase a Google Mobile Ads...
import Firebase
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
GADMobileAds.configure(withApplicationID: "ca-app-pub-8482280186158418~7106629637")
GADMobileAds.sharedInstance().start(completionHandler: nil)
}
}
I have also added my GADApplicationIdentifier to my Info.plist. In my storyboard, I have a ViewController that contains a UICollectionViewCell that contains a GADUnifiedNativeAdView and the native elements are linked through outlets.
Over in my ViewController, in the viewDidLoad, I load 5 native ads.
override func viewDidLoad() {
super.viewDidLoad()
// Load Ads
let adUnitID = "ca-app-pub-{adUnitId}"
let numAdsToLoad = 5
let options = GADMultipleAdsAdLoaderOptions()
options.numberOfAds = numAdsToLoad
let imageOptions = GADNativeAdImageAdLoaderOptions()
imageOptions.disableImageLoading = false
let mediaOptions = GADNativeAdMediaAdLoaderOptions()
mediaOptions.mediaAspectRatio = .square
let adOptions = GADNativeAdViewAdOptions()
adOptions.preferredAdChoicesPosition = .topLeftCorner
adLoader = GADAdLoader(adUnitID: adUnitID, rootViewController: self, adTypes: [.unifiedNative], options: [options, imageOptions, mediaOptions])
adLoader.delegate = self
adLoader.load(GADRequest())
}
Over in the GADUnifiedNativeAdLoaderDelegate, I receive the ad and ad them to an array.
var nativeAds = [GADUnifiedNativeAd]()
extension ViewController: GADUnifiedNativeAdLoaderDelegate {
func adLoader(_ adLoader: GADAdLoader,
didFailToReceiveAdWithError error: GADRequestError) {
print("NATIVE AD - didFailToReceiveAdWithError: \(error)")
}
func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADUnifiedNativeAd) {
print("NATIVE AD - didReceive: \(nativeAd)")
nativeAds.append(nativeAd)
}
func adLoaderDidFinishLoading(_ adLoader: GADAdLoader) {
print("NATIVE AD - adLoaderDidFinishLoading")
libraryCollection.reloadData()
}
}
In my UICollectionView's delegate, in cellForItemAt I set the cell's class
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if isAdCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "adCell", for: indexPath) as! AdCollectionViewCell
if nativeAds.count == 5 {
cell.nativeAd = nativeAds[0]
cell.nativeAd.rootViewController = self
}
cell.setAdData()
return cell
}
Finally, in my UICollectionViewCell's class, I set the ad data
import Firebase
class AdCollectionViewCell: UICollectionViewCell {
#IBOutlet var adView: GADUnifiedNativeAdView
var nativeAd = GADUnifiedNativeAd()
func setAdData() {
adView.nativeAd = nativeAd
(adView.headlineView as! UILabel).text = nativeAd.headline
adView.callToActionView?.isUserInteractionEnabled = false
(adView.callToActionView as! UILabel).text = nativeAd.callToAction
adView.mediaView?.mediaContent = nativeAd.mediaContent
adView.mediaView?.contentMode = .scaleAspectFill
}
}
The Error
Now, whenever I use the test native ad unit id provided by Google AdMob, ca-app-pub-3940256099942544/3986624511, everything works just fine! I get no errors and the system prints
NATIVE AD - didReceive: <GADUnifiedNativeAd: 0x283bbdc00>
NATIVE AD - didReceive: <GADUnifiedNativeAd: 0x283bbd7a0>
NATIVE AD - didReceive: <GADUnifiedNativeAd: 0x283bc73a0>
NATIVE AD - didReceive: <GADUnifiedNativeAd: 0x283ba9880>
NATIVE AD - didReceive: <GADUnifiedNativeAd: 0x283ba9810>
NATIVE AD - adLoaderDidFinishLoading
But the problem comes when I try to use my own native ad unit id. Upon loading, the system prints the error
NATIVE AD - didFailToReceiveAdWithError: Error Domain=com.google.admob Code=1 "Request Error: No ad to show." UserInfo={NSLocalizedDescription=Request Error: No ad to show., gad_response_info= ** Response Info **
Response ID: ymbzXou2CcrohQb16bzgBA
Network: (null)
** Mediation line items **
Entry (1)
Network: GADMAdapterGoogleAdMobAds
Credentials:
{
}
Error: Error Domain=com.google.admob Code=1 "Request Error: No ad to show." UserInfo={NSLocalizedDescription=Request Error: No ad to show.}
Latency: 0.095
}
for each ad that I load. And I have tried MANY things to fix this that I have found all over the internet...
Troubleshooting
As I mentioned, I have scoured the internet for help and troubleshooting options. Here is what I have done.
Created a new native ad unit id
Waited over a week to confirm the error with the unit id
Checked my AdMob and AdSense account information
Checked my AdMob and AdSense payment information
Made sure the GADApplicationIdentifier in the Info.plist is correct
Added all of the requirements to the App Transport Security Settings in the Info.plist as laid out by AdMob. (Allow Arbitrary Loads, Allows Arbitrary Loads for Media, Allow Arbitrary Loads in Web Content)
Double, triple, quadruple, quintuple checked the code and followed the documentation provided by AdMob
Followed the CodeLab provided by AdMob
I had the same problem with error-code 1. Also after i had published my app in appstore. The test-ads worked fine. After i could linked my app with the app store (8 days after publishing) it worked.
It seems that you just don't get the ad. It depends on many factors like your country, your device, your IDFA or any other kind of information that AdMob might have collected. From the advertiser's perspective, you aren't an attractive audience.
If you want to increase your chances of getting an ad you can us VPN to high demand area, e.g. USA.
Hello dear developers,
I'm currently stuck due to a problem with In-App AppStore rating (SKStoreReviewController).
Here is the situation, I've a screen "FirstScreen" with a button. When I tap on it, I'm going to the next screen "SecondScreen" and an in app alert for AppStore rating pop over.
I'm trying to find a solution for my UITests in order to dismiss this Alert.
I tried many solutions but I'm looking for one which do not depends on string (I don't want to localize the content of this Alert):
override func setUp() {
app = XCUIApplication()
app.launch()
addUIInterruptionMonitor(withDescription: "System Dialog") { (alert) -> Bool in
let allowButton = alert.buttons.element(boundBy: 1)
if allowButton.exists {
allowButton.tap()
}
}
}
I also tried to add an interaction ("app.swipeUp()") when I'm coming to "SecondScreen" in order to trigger this handler.
I've also tried another solution, as I know when this alert will be triggered:
let dismissButton = XCUIApplication(bundleIdentifier: "com.apple.springboard").buttons.element(boundBy: 1)
if dismissButton.exists {
dismissButton.tap()
}
No one worked and I'm still stuck :(
Does anybody found a solution in order to dismiss this alert ?
Thanks
Swiping up doesn't work but ironically swiping down does. Here is a very simplistic example
import UIKit
import StoreKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) {
SKStoreReviewController.requestReview()
}
}
}
import XCTest
class UITests: XCTestCase {
override func setUp() {
continueAfterFailure = false
}
func test() {
let app = XCUIApplication()
app.launch()
sleep(5)
app.swipeDown()
sleep(3)
}
}
I am getting Thread 1: signal SIGABRT error on appDelegate, I think it is because of facebook login button which I have been trying to connect to my xcode project through facebook sdk. I dont know if the way i am connecting facebook login button through outlet is correct or not. because at first it was giving me an error of optional unwrapping, when I avoided it by adding ? in the code below
fbloginbtnview?.delegate = self
fbloginbtnview?.permissions = ["email"]
now I get signal SIGABRT error.
I have been watching all the tutorials and reading all the questions on stackoverflow, but can not find anything helpful to connect facebook login button, because al the helps available are either for older versions of swift and xcode or I dont get axactly what i want.
my swift version is 5, and xcode 9.3
can anyone please give me a right peice of code to connect a facebook login button?
This is appdelegate
import UIKit
import Firebase
import CoreData
import FirebaseAuth
import FacebookCore
import FBSDKCoreKit
import FBSDKLoginKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
//below for fb sdk
//....
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
return true
}
//....
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool {
guard let urlScheme = url.scheme else { return false }
if urlScheme.hasPrefix("fb") {
return ApplicationDelegate.shared.application(app, open: url, options: options)
}
return true
}
// above for fb sdk nothing
//
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
// Saves changes in the application's managed object context before the application terminates.
self.saveContext()
}
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentContainer(name: "LetsGoTogether")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
// MARK: - Core Data Saving support
func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}
This below is my View controller code
import UIKit
import Firebase
import FBSDKLoginKit
import FacebookCore
class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate, LoginButtonDelegate {
#IBOutlet var fbloginbtnview: FBLoginButton!
override func viewDidLoad() {
super.viewDidLoad()
// fb
fbloginbtnview?.delegate = self
fbloginbtnview?.permissions = ["email"]
}
func loginButton(_ loginButton: FBLoginButton, didCompleteWith result: LoginManagerLoginResult?, error: Error?) {
if let error = error {
print("error took place\(error.localizedDescription)")
return
}
print("Success")
}
func loginButtonDidLogOut(_ loginButton: FBLoginButton) {
print("user signed out")
}
}
You have declared fbloginbtnview as an implicit optional, which is normal but means it is assumed to be valid. References to it will fail if you haven't connected the outlet to an actual button (or to a button of the right type) in interface builder.
I am trying to integrate the Unity build for iOS into a pre-existing native app. I am using two buttons to start and stop the unity, but when I click on start, Unity view comes on the top of the current view and both the buttons disappear behind it. I used Unity 2019.1.11f1 for building the unity project.
Below is my App Delegate Code:
//
// AppDelegate.swift
// blue
//
// Created by Vikas Roy on 01/07/19.
// Copyright © 2019 MedleyOne. All rights reserved.
//
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var application: UIApplication?
#objc var currentUnityController: UnityAppController!
var isUnityRunning = false
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.application = application
unity_init(CommandLine.argc, CommandLine.unsafeArgv)
currentUnityController = UnityAppController()
currentUnityController.application(application, didFinishLaunchingWithOptions: launchOptions)
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
if isUnityRunning {
currentUnityController.applicationWillResignActive(application)
}
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
if isUnityRunning {
currentUnityController.applicationDidEnterBackground(application)
}
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
if isUnityRunning {
currentUnityController.applicationWillEnterForeground(application)
}
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
if isUnityRunning {
currentUnityController.applicationDidBecomeActive(application)
}
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
func startUnity() {
if !isUnityRunning
{
isUnityRunning = true
currentUnityController.applicationDidBecomeActive(application!)
}
}
func stopUnity() {
if isUnityRunning {
currentUnityController.applicationWillResignActive(application!)
isUnityRunning = false
}
}
}
Below is the View Controller Code:
//
// Unity3DViewController.swift
// blue
//
// Created by Vikas Roy on 25/07/19.
// Copyright © 2019 MedleyOne. All rights reserved.
//
import UIKit
class Unity3DViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
func showUnitySubView() {
if let unityView = UnityGetGLView() {
view?.insertSubview(unityView, at: 0)
}
}
#IBAction func StartUnity(_ sender: Any) {
if let appDelegate = UIApplication.shared.delegate as? AppDelegate
{
appDelegate.startUnity()
showUnitySubView()
}
}
#IBAction func StopUnity(_ sender: Any) {
if let appDelegate = UIApplication.shared.delegate as? AppDelegate
{
appDelegate.stopUnity()
}
}
}
I want buttons to always stay on the top of the unity view. Any idea where the issue can be?
In ViewContoller, where Unity is loading,
create an outlet of your button
and call this function in viewDidload() this way:
let unityView = UnityGetGLView()
unityView.addsubView(yourbutton)
I've been working on the following problem for a couple of days now and I'm getting a little upset with it. So I have a project file https://github.com/PCmex/lift-side-memu-in-swift-3 and I successfully initiated Cocoapod with it. I followed the whole admob tutorial and did all the required steps. When I try to test the app the build is OK, but after the app launches it crashes and gives me the following information:
Screenshot for error message: Thread 1: EXC_BAD_INSTRUCTION
The log gives me the following information:
Google Mobile Ads SDK version:(GADRequest.sdkVersion())
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
Here is the app delegate.swift
import UIKit
import GoogleMobileAds
import Firebase
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
//Use Firebase library to configure APIs
FirebaseApp.configure()
GADMobileAds.configure(withApplicationID: "ca-app-pub-***")
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
And this is the ViewController.swift
import UIKit
import GoogleMobileAds
import Firebase
class ViewController: UIViewController {
#IBOutlet weak var btnMenuButton: UIBarButtonItem!
#IBOutlet weak var bannerView: GADBannerView!
override func viewDidLoad() {
super.viewDidLoad()
// Aanroepen print functie voor de Google AdMob banner
print("Google Mobile Ads SDK version:(GADRequest.sdkVersion())")
bannerView.adUnitID = "ca-app-pub-***"
bannerView.rootViewController = self
bannerView.load(GADRequest())
// Do any additional setup after loading the view, typically from a nib.
if revealViewController() != nil {
// revealViewController().rearViewRevealWidth = 62
btnMenuButton.target = revealViewController()
btnMenuButton.action = #selector(SWRevealViewController.revealToggle(_:))
// revealViewController().rightViewRevealWidth = 150
// extraButton.target = revealViewController()
// extraButton.action = "rightRevealToggle:"
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I'm pretty sure I've been installing cocoa-pod / AdMob and all prerequisites correctly. When I do all steps in a new project everything works fine. But I'm trying to understand why it doesn't work in my current project. Hope someone could point me in the right direction, thanks in advance!
The variable bannerView is an implicitly unwrapped optional. That means that it is an optional variable type. Remember that unwrapping optionals will crash if its value is nil, so normally you would do some optional chaining like if let to test before unwrapping to prevent crashing. In your case, bannerView is nil, so your application crashed. An implicitly unwrapped optional is declared by placing a ! after its type (in your case, GADBannerView!).
I suggest you to go to the storyboard (or XIB) of your controller, select your GADBannerView and go to the connections inspector
And check if there is anything in the "Referencing Outlets" section (except for "New Referencing Outlet). If there is, break the connection by clicking the X button.
Then delete the #IBOutlet weak var bannerView line in the Controller and reconnect the GADBannerView to ViewController. If there is nothing in the section, simply delete #IBOutlet weak var bannerView and reconnect the GADBannerView to ViewController