I'm working on implementing ATTrackingManager to display Google AdMob banner ads in my project.
Here's my setup thus far:
func requestAds() {
appDelegate.adBannerView.adUnitID = GlobalVariables.bannerAdUnitID
appDelegate.adBannerView.rootViewController = self
appDelegate.adBannerView.adSize = GADPortraitAnchoredAdaptiveBannerAdSizeWithWidth(view.frame.size.width)
if #available(iOS 14, *) {
ATTrackingManager.requestTrackingAuthorization(completionHandler: { status in
self.appDelegate.adBannerView.load(GADRequest())
// Add to view
self.view.addSubview(self.appDelegate.adBannerView)
})
} else {
self.appDelegate.adBannerView.load(GADRequest())
// Add to view
self.view.addSubview(self.appDelegate.adBannerView)
}
}
I'm calling this within viewDidLoad()
The permission alert displays properly. However, before I select an option for either Ask App Not to Track or Allow, I can see the banner is already displayed on the main View Controller.
This doesn't seem like the intended behavior.. Shouldn't the banner load after the user submits a response for Ask App Not to Track or Allow?
How can I prevent ads from loading & displaying until the user submits a response for the Privacy - Tracking Usage Description alert?
Related
Hi I am using UIActivityViewController to share content on social networks but facing one issue. The issue is when i select the share button the UIActivityViewController gets appear and I select the Facebook option.
I select the Facebook option in the sharing sheet -> Facebook sharing view appears with two options (Cancel and Next). When I select the Cancel button giving me another action sheet to discard or keep the post. When i select to discard the Action Sheet get disappear but the Facebook sharing view still keep showing and there is no way to go back.
Second when I press the next button in the Facebook sharing view -> another Facebook view gets appear with two buttons (Cancel and Share).... When I click the share button content get share on Facebook and black screen appears with a check in circle and text "Shared to Facebook!" .. And the application get stuck on this Screen.
Below is my code, Any help would be appreciated, I am also using the activityViewController!.completionWithItemsHandler but this closure not getting called in case of Facebook.
let url = "\(UserDefaults.baseURL)/pl/\(resource)/\(sharingId)"
// set up activity view controller
let imageToShare = [ url ]
activityViewController = UIActivityViewController(activityItems: imageToShare, applicationActivities: nil)
activityViewController!.popoverPresentationController?.sourceView = self.view // so that iPads won't crash
// exclude some activity types from the list (optional)
activityViewController!.excludedActivityTypes = [UIActivity.ActivityType.airDrop]
activityViewController!.completionWithItemsHandler = { (activityType: UIActivity.ActivityType?, completed:
Bool, arrayReturnedItems: [Any]?, error: Error?) in
if completed {
print("share completed")
self.dismiss(animated: true)
return
} else {
print("cancel")
self.dismiss(animated: true)
}
if let shareError = error {
print("error while sharing: \(shareError.localizedDescription)")
}
}
// present the view controller
self.present(activityViewController!, animated: true, completion: nil)
I am trying to listen for global keyboard events and make my app do specific things when certain key presses are detected. to do this, I would like to use:
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
//Add keyboard event listener.
NSEvent.addGlobalMonitorForEvents(matching: .keyDown, handler:
{
print("key down!");
print($0.keyCode);
});
}
}
and I am checking for accessibility permissions in my appDelegate.swift this way:
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
//check if the process is trusted for accessibility. This is important for us to listen for keyboard events system wide.
let checkOptPrompt = kAXTrustedCheckOptionPrompt.takeUnretainedValue() as NSString
let options = [checkOptPrompt: true]
let isAppTrusted = AXIsProcessTrustedWithOptions(options as CFDictionary?);
if(isAppTrusted != true)
{
print( "please allow accessibility API access to this app.");
}
}
I went ahead and granted Xcode accessibility permissions in system preferences. I however see the log statement asking to grant accessibility permissions to this app. simply put, here is my big question, divided into two smaller questions:
How do I give this app full privileges (give accessibility permissions)?
How do I show a pop-up asking the user to grant accessibility permissions if they are not enabled?
I recently sent my app to beta testing and I put ads (Google AdMob) in it. At first, when my testers used it, they used to see the ads, but when I did it, I didn't see them (on my phone, while on the simulator they work fine).
Now they just see them sometimes (while I still can't see them on my iPhone). I thought it was because I blocked some ads categories, so I checked and I noticed I had to allow the ads I wanted to show, but some testers still couldn't see them (or they could for a while and after a few minutes they would disappear).
So I thought of another solution: I added a view that would only show if the ads weren't loaded, tested on simulator ad everything was nice, sent it to beta and new errors came up: now they could see ads but after a while they would disappear showing the other view, and this is fine. But after some time the ad showed over the new view or they would randomly stop appearing (after they appeared).
So, what I would like to know is:
(Not really important, just curiosity) Why don't I see ads when I test my own app on my iPhone?
(Main question)How can I display another banner-like view when my ads don't load? Or even is there a way to always display them?
My code is the same you can find in the Google AdMob tutorial but I edited to add the other banner-like view:
//This is to remove the banners when the user purchases the app or to show them if he has the free version
override func viewWillAppear(_ animated: Bool) {
if defaults.value(forKey: purchaseKey) == nil {
bannerView = GADBannerView(adSize: kGADAdSizeSmartBannerPortrait)
addBannerViewToView(bannerView)
bannerView.delegate = self
bannerView.adUnitID = "myID"
bannerView.rootViewController = self
bannerView.load(GADRequest())
} else {
bannerView.isHidden = true
removeAdsView.isHidden = true
}
}
/// Tells the delegate an ad request loaded an ad.
func adViewDidReceiveAd(_ bannerView: GADBannerView) {
print("adViewDidReceiveAd")
removeAdsView.isHidden = true
addBannerViewToView(bannerView)
bannerView.alpha = 0
UIView.animate(withDuration: 1, animations: {
bannerView.alpha = 1
})
}
/// Tells the delegate an ad request failed.
func adView(_ bannerView: GADBannerView,
didFailToReceiveAdWithError error: GADRequestError) {
print("adView:didFailToReceiveAdWithError: \(error.localizedDescription)")
removeAdsView.isHidden = false
}
Read your log, there must be some error descriptions from Google, in my case I added my device as test
let request = GADRequest()
request.testDevices = ["5bb6d1ce5935f98196d35d9e61ac74f6"]
bannerView?.load(request)
Also you should turn off ad filter on your iPhone, Settings -> Privacy -> Ad
My developer and I had previously tried to get interstitial adverts loading on iPhone and iPad, however only managed to get this working on iPad.
During our testing we discovered that interstitials weren't supported on iPhone, but since the release of iOS7 some people now say this is possible.
However I can't find any decent documentation on this. This Stack question has got me wondering again though iAd & Admob Interstitial Integration on iPhone
So, are full screen interstitials possible on iPhone using iAds?
I've also been waiting for interstitial ads for iPhone from iAd. I finally have it implemented into one of my apps and it is running and showing test ads just fine. The app is currently in review and I will update my answer once it is approved and I can test if any actual ads are being served. In the meantime, here is the code I used to implement iAd interstitials:
ViewController.h
#interface ViewController : UIViewController <ADInterstitialAdDelegate> {
ADInterstitialAd *interstitial;
BOOL requestingAd;
}
-(void)showFullScreenAd;
ViewController.m
-(void)viewDidLoad {
requestingAd = NO;
}
// Interstitial iAd
-(void)showFullScreenAd {
// Check if already requesting ad
if (requestingAd == NO) {
[ADInterstitialAd release];
interstitial = [[ADInterstitialAd alloc] init];
interstitial.delegate = self;
self.interstitialPresentationPolicy = ADInterstitialPresentationPolicyManual;
[self requestInterstitialAdPresentation];
NSLog(#"interstitialAdREQUEST");
requestingAd = YES;
}
}
-(void)interstitialAd:(ADInterstitialAd *)interstitialAd didFailWithError:(NSError *)error {
interstitial = nil;
[interstitialAd release];
[ADInterstitialAd release];
requestingAd = NO;
NSLog(#"interstitialAd didFailWithERROR");
NSLog(#"%#", error);
}
-(void)interstitialAdDidLoad:(ADInterstitialAd *)interstitialAd {
NSLog(#"interstitialAdDidLOAD");
if (interstitialAd != nil && interstitial != nil && requestingAd == YES) {
[interstitial presentFromViewController:self];
NSLog(#"interstitialAdDidPRESENT");
}
}
-(void)interstitialAdDidUnload:(ADInterstitialAd *)interstitialAd {
interstitial = nil;
[interstitialAd release];
[ADInterstitialAd release];
requestingAd = NO;
NSLog(#"interstitialAdDidUNLOAD");
}
-(void)interstitialAdActionDidFinish:(ADInterstitialAd *)interstitialAd {
interstitial = nil;
[interstitialAd release];
[ADInterstitialAd release];
requestingAd = NO;
NSLog(#"interstitialAdDidFINISH");
}
I just call -(void)showFullScreenAd after the user performs a certain action. For more information refer to UIViewController iAd Additions Reference
EDIT: 01/03/14
The app update was approved and has been live for 12 hours now. I still have not received any interstitial iAds as of this moment. It may be due to the lack of inventory for interstitial ads on iPhone or it may have something to do with the following message I've received in my iAd module on iTunes Connect. The message reads
When you submit your app, [app name], for approval, it will also be reviewed by iAd for use on the App Network to determine its appropriateness for receiving ads from iAd advertisers. Once your app is approved, you will be ready to start earning revenue for ads that run in your app.
I've never received this message before, I usually receive the "Your app is now eligible to receive ads" message as soon as the update is released in the App Store. It's either because of the new implementation of interstitial ads in my app or Apple has updated some of its iAd procedures.
Will update answer again if and when I do start receiving interstitial iAds. In the meantime you may test it yourself on my app +Quotes. The above code is invoked and an interstitial ad should show once a user shares via Facebook within the app.
EDIT: 01/07/14
Contacted iAd directly and received a response today
Hello Daniel,
Initial fill rates will reflect the recent launch of interstitials on iOS 7. Thank you for your patience as we ramp up ad serving.
If you haven't already, we recommend you integrate standard portrait and landscape iAd banners in your app to take advantage of all available types of advertising inventory.
Finally, for future reference, when you submit your app for approval, it will also be reviewed by iAd to determine its appropriateness for receiving ads from iAd advertisers. Therefore, it may take a few days for your new iAd enabled app to begin receiving ad impressions.
Best Regards,
iAd App Network Support
So, interstitial iAds for iPhone do work with iOS 7.0 and above but have a low fill rate currently.
My original answer is starting to age away so here's a newer Swift implementation:
This implementation uses a Manual ADInterstitialPresentationPolicy so we can present our interstitials at our own intervals. When manually presenting your interstitial it does not load with its own close button to dismiss itself. So, what I've done is created a UIView to present the interstitial in and used the interstitial's delegate methods to dismiss the UIView. The inconsistency with receiving an ad from the iAd network still arises when testing. Sometimes you receive an ad, sometimes it fails to load which allows us to request a new ad, and sometimes nothing happens at all. This just seems to be the nature of iAd's interstitials.
import UIKit
import iAd // Import iAd
class ViewController: UIViewController, ADInterstitialAdDelegate { // Include the delegate
var iAdInterstitial = ADInterstitialAd() // Our ad
var iAdInterstitialView = UIView() // View to present our ad in
var adLoaded = false // Bool to keep track if an ad is loaded or not
override func viewDidLoad() {
super.viewDidLoad()
setupAd()
}
func setupAd() {
// Set presentation to manual so we can choose when to present the interstitial
// Setting this will also fetch an interstitial ad for us
self.interstitialPresentationPolicy = ADInterstitialPresentationPolicy.Manual
iAdInterstitial.delegate = self // Set the delegate
// Make our view the same size as the view we will be presenting in
iAdInterstitialView.frame = self.view.bounds
}
func requestNewAd() {
// This will fetch an ad for us
ViewController.prepareInterstitialAds()
println("Requesting new ad")
}
#IBAction func presentAdButton(sender: AnyObject) {
if (adLoaded) {
// We have an ad that is loaded so lets present it
self.view.addSubview(iAdInterstitialView)
iAdInterstitial.presentInView(iAdInterstitialView)
}
else {
// No ad has been loaded
println("Ad not loaded")
}
}
func interstitialAdDidUnload(interstitialAd: ADInterstitialAd!) {
// Kinda works as expected
// Sometimes is called prematurely
// Sometimes takes minutes after ad is dismissed to be called
println("interstitialAdDidUnload")
// Get new ad
adLoaded = false
iAdInterstitialView.removeFromSuperview()
requestNewAd()
}
func interstitialAd(interstitialAd: ADInterstitialAd!, didFailWithError error: NSError!) {
// Failed to load ad so lets try again
println("didFailWithError: \(error)")
requestNewAd()
}
func interstitialAdWillLoad(interstitialAd: ADInterstitialAd!) {
// There is an ad and it has begun to download
println("interstitialAdWillLoad")
}
func interstitialAdDidLoad(interstitialAd: ADInterstitialAd!) {
// We got an ad
println("interstitialAdDidLoad")
adLoaded = true
}
func interstitialAdActionShouldBegin(interstitialAd: ADInterstitialAd!, willLeaveApplication willLeave: Bool) -> Bool {
println("interstitialAdActionShouldBegin")
return true;
}
func interstitialAdActionDidFinish(interstitialAd: ADInterstitialAd!) {
// Done with this ad. Lets get a new one
println("interstitialAdActionDidFinish")
iAdInterstitialView.removeFromSuperview()
adLoaded = false
requestNewAd()
}
I've built my app this way and everything seems to be working more or less. After hearing about the notoriously low iAd fill rate I decided that this would be the best method, but I tried googling it and i couldnt find record of anyone else implementing ads in their app like this. Does this violate the TOS?
Why not use Adwhirl. Its great sdk that enables you to do exactly what you need. You can set priority settings for different ad networks which can be changed on the fly if you find one network performing better than others etc.
It handles all the logic for which ad to show based on request failure or priority without you needing to worry about it. All you do is create an adwhirl view and request an ad. Adwhirl does the rest, including appropriate refreshing. If an iAd fails first time, and then shows an admob, but the next iAd loads successfully, it will be shown instead of the admob, assuming you set iAd as a higher priority network.
http://adwhirl.com
Are you hiding the ADBannerView by setting visible to NO? With the ADBannerView, if you set visible to NO, then it stops asking for ads. To "hide" the ADBannerView, you need to translate it to someplace off screen.
You can use these controls to show iAds as well as adMob both
iAdPlusAdMob
CJPAdController
Or here is nice tut that explain step by step
http://mobile.tutsplus.com/tutorials/iphone/supplementing-iad-placement-with-admob/
I have iAds and Admob.
I highly recommending loading an iAd first and if you dont get an Ad use admob. iAd has a much higher ECPM than admob if you get an ad. Remember that iAd refreshes every 30s so the did not get ad method will be called several times.
My app has been approved you can get it, Octopus Oracle.
http://kurl.ws/Ay
You can use AdWhirl
and its best tutorial is here
Tutorial
I ended up with this strategy:
first of all I have created 2 outlets from the storyboard, one for the ADBannerView and another for the GADBannerView
#IBOutlet weak var iadBannerView: ADBannerView!
#IBOutlet weak var adMobBannerView: GADBannerView!
In your viewDidLoad you can do this:
override func viewDidLoad() {
super.viewDidLoad()
self.iadBannerView.hidden = true
self.adMobBannerView.hidden = true
self.iadBannerView.delegate = self
NSTimer.scheduledTimerWithTimeInterval(35, target: self, selector: Selector("dispalyGoogleBanner"), userInfo: nil, repeats: false)
}
So here you hidden both banners (if you prefer you can do it directly in storyboard). then you wait 35 second before to display the google ads. So before to display the google ads you basically want to see if iAD it's available.
this is the method used to display the google banner:
//MARK: - Google banner
func dispalyGoogleBanner() {
if !self.isDisplayIAD && !idDisplayADMob {
idDisplayADMob = true
self.adMobBannerView.adUnitID = kAdUnitID
self.adMobBannerView.hidden = false
self.adMobBannerView.rootViewController = self
self.adMobBannerView.loadRequest(GADRequest())
}
}
so before to display the google banner, we ensure that the iAD banner and the adMob banner are not displayed yet. If that it's the case, then we can send the request to display the ADMob banner.
Here my implementation of the ADBannerViewDelegate
func bannerViewDidLoadAd(banner: ADBannerView!) {
self.iadBannerView = banner
self.iadBannerView.hidden = false
self.adMobBannerView.hidden = true
idDisplayADMob = false
self.view.layoutIfNeeded()
}
func bannerView(banner: ADBannerView!, didFailToReceiveAdWithError
error: NSError!) {
println(error)
isDisplayIAD = false
self.iadBannerView.hidden = true
self.dispalyGoogleBanner()
}
func bannerViewActionDidFinish(banner: ADBannerView!) {
self.iadBannerView = banner
self.iadBannerView.hidden = true
isDisplayIAD = false
dispalyGoogleBanner()
}
func bannerViewWillLoadAd(banner: ADBannerView!) {
//remove the google banner if displayed
isDisplayIAD = true
self.iadBannerView.hidden = false
self.adMobBannerView.hidden = true
idDisplayADMob = false
self.view.layoutIfNeeded()
}
what I basically did on these delegates it's to check if the iAD banner it's available, if that it's case then I'll hidden the adMob banner. If the iAD finished to display the ads, then I'll call the ADMob banner see bannerViewActionDidFinish
You can easily adapt this logic tu your implementation.