Removing RevMob Ad banner upon in-App purchase - ios

The problem is that Apple rejects my app because when the button is clicked to purchase the "no ads" upgrade, it doesn't make the banner disappear until you close the app and re-open it. This is because I initialize all my RevMob code in the viewController.swift file. I have a boolean in place that turns to false as soon as the upgrade is purchase inside this viewController.swift file. So next time you open the app and the viewController loads, the boolean is set to false and it doesn't allow the ads to appear.
Anybody know if this is the wrong way to go about this? Or is there an easy way to make them disappear immediately upon press of the no Ads button without having to close the app and re-open it?
//BANNER AD =======================================
let bannerBlock: () -> Void = {
//Custom method defined below
if UserDefaults.standard.object(forKey: "adsBool") as! Bool == true
{
self.showBannerWithCustomFrame()
}
else
{
//don't show ads because user purchased
}
}
let bannerFailBlock: ((Error?) -> Void) = {error in
NSLog("[RevMob Sample App] Session failed to start with error: \(error!.localizedDescription)")
}
RevMobAds.startSession(withAppID: "00000000000000000000",
withSuccessHandler: bannerBlock,
andFailHandler: bannerFailBlock)
This is how my bannerView is set up in my GameViewController
class GameViewController: UIViewController, RevMobAdsDelegate {
var bannerView:RevMobBannerView?
override func viewDidLoad() {
super.viewDidLoad()

From RevMob's banner documentation, there's a method called hideAd. Calling that method on the IAP callback would solve your problem right?
To hide the banner:
banner!.hideAd()

Let me see if i got your problem correctly, you want to hide your banner as soon as the purchase is made.
First, you need to set the bannerView as a property of your viewController.
Then you have to add this code inside the callback from the purchase success:
viewController.bannerView.removeFromSuperview();

I fixed it! Thanks for your help. I had to move the code from the GameViewController to the GameScene for the bannerAd so that I could remove it as soon as the purchase was made. Works perfectly.

Related

Live Admob Ads have suddenly stopped displaying in my app

In June, Admob adverts worked perfectly and AdMob sent a letter with a verification PIN for me to verify my identity & payment details.
Around the beginning of July, nearly all live ads stopped displaying in my app. I am still making the same number of requests, but impressions are so low I have dropped to £0.00/£0.01 a day. All test ads work correctly.
This issue began around the time I renamed my app (only on the app store display), however; all links to my app in my AdMob account are correct so the name change appears to have made no difference on their front-end UI.
When I debug my app, I get a list of warnings in the output section:
[I-ACS025031] AdMob App ID changed. Original, new: (nil), AppId
My 'GADApplicationIdentifier' value in my info.plist is the same as the 'new' app id.
[I-ACS013003] User property name must start with a letter: _ap
I am not setting any user properties, no idea what this means.
What have I tried?
Setting up new ad units.
Reverting back to an older version of the app.
Contacted AdMob 'support' via a form. They told me my ad serving is being limited. They did not say for how long and it has been around 2/3 weeks (by 'limited', I don't think they meant completely stopped).
Checked for policy violations in my account; nothing is there.
Code I use to display ads:
I have created an 'AdMobDisplayer' class that allows me to set up and display ads; this is called by each view controller. For example, my banner ads code:
View Controller:
let adMobDisplayer = AdMobDisplayer()
#IBOutlet weak var bannerView: GADBannerView!
override func viewDidLoad() {
super.viewDidLoad()
self.bannerView = self.adMobDisplayer.setupAdBannerView(self.bannerView, viewController: self, adUnitId: Constants.timerTabBannerAdId)
self.adMobDisplayer.displayBannerAd(self.bannerView)
}
AdMobDisplayer:
func setupAdBannerView(_ bannerView: GADBannerView, viewController: UIViewController, adUnitId: String, bannerViewDelgate: GADBannerViewDelegate? = nil) -> GADBannerView {
if(checkIfAdsAreDisabled()) {
return bannerView
}
/// Creates a new GADBannerView to be displayed in a view controller
bannerView.adUnitID = adUnitId
/// bannerView.adUnitID = Constants.testBannerAdId
bannerView.rootViewController = viewController
if let delegate = bannerViewDelgate {
bannerView.delegate = delegate
}
return bannerView
}
func displayBannerAd(_ bannerView: GADBannerView) {
if(checkIfAdsAreDisabled()) {
return
}
///Creates a request and loads an advert from AdMob
let request = GADRequest()
request.testDevices = [ "My Device Id" ]
bannerView.load(request)
}
This should display a banner ad in the view. It worked when I first added adverts in, it works for test adverts, but intermittently/rarely for live adverts now.
Find the full application on my GitHub: https://github.com/AlexMarchant98/KeGal-Trainer
Thanks in advance for any help!
I recently worked on GADBannerView in my last app and had almost similar issue, in your case you may need to generate Admob ad id, from their website.
So I fixed this ages ago, but, my fix was to add the required 'NSAppTransportSecurity' keys into my info.plist.
https://developers.google.com/admob/ios/app-transport-security

UITest cases to handle with location services alert

I am writing UI test cases for my project.
My project flow is as below:
Login Screen. User enters credentials and press login.
Home Screen. There is location requirement so system as for user's permission. I allow it.
Logout.
So when I do fresh install of application this flow is recorded in test case and works if I perform on new fresh build.
But problem is when I test on old build there is no alert for location permission and the test's gets fail. How can I handle this cases or ask user for permission every time when I run tests?
For resetting credentials of user I am passing launchArguments to XCUIApplication() and handle in AppDelegate.
I have implemented code let me know if its correct way:
addUIInterruptionMonitor(withDescription: "Allow “APP” to access your location?") { (alert) -> Bool in
alert.buttons["Only While Using the App"].tap()
return true
}
The above code works for both if alert comes or not.
Using an interruption monitor is the correct way. However, it's safer to check if the alert being displayed is the alert you're expecting before you interact with the alert:
addUIInterruptionMonitor(withDescription: "Allow “APP” to access your location?") { (alert) -> Bool in
let button = alert.buttons["Only While Using the App"]
if button.exists {
button.tap()
return true // The alert was handled
}
return false // The alert was not handled
}
Try this
let app2 = XCUIApplication(bundleIdentifier: "com.apple.springboard")
let button = app2.alerts.firstMatch.buttons["Allow While Using App"]
button.waitForExistence(timeout: 10)
button.tap()
I use the following code to allow user's location:
// MARK: - Setup
override func setUp() {
super.setUp()
continueAfterFailure = false
app = XCUIApplication()
app.launch()
addUIInterruptionMonitor(withDescription: "System Dialog") { (alert) -> Bool in
alert.buttons["Allow Once"].tap()
return true
}
}
In this setup, I "register" the interruption monitor for tapping the allow button, so in this case I can dismiss that modal. Now, there's my test:
// MARK: - Test change mall
func testChangeMall() {
let selectorChangeButton = app.buttons["change_mall_button"]
XCTAssert(selectorChangeButton.exists, "Selector change button does not exist")
selectorChangeButton.tap()
app.navigationBars.firstMatch.tap()
let cell = app.staticTexts["Shopping Centre"]
XCTAssert(cell.exists, "There's no cell with this title")
cell.tap()
sleep(1)
let label = app.staticTexts["Shopping Centre"]
XCTAssert(label.exists, "Nothing changes")
}
In this test, simply I go to a view controller with a list sorted by location. First, I need to dismiss the location's system alert. So, first I dismiss that modal and then I tap a cell from my TableView. Then, I need to show it in my main view controller so I dismiss my view controller and I expect the same title.
Happy Coding!

How to free scene until Interstitial is dismissed?

So I have a an app that uses interstitial ads. Specifically it is a a SpriteKit game written with Swift.
I have code setup that when the user presses the replay button from the game over scene an ad appears and then it changes back to the game scene to replay the game. Now where I am running into problems the scene changes while the interstitial ad is being displayed, sometimes this doesn't happen fast enough and user can tap the restart button again, causing the game to crash.
Is there a way to freeze the screen and ignore any taps while the ad is being called? And also to only have the scene change after the ad is dismissed?
The code when the restart button is pressed;
if restartButton.contains(pointOfTouch) {
score = 0
ballMovementSpeed = 2
displayAd()
delay(2.0) {
self.restartScene()
}
I am a bit confused as to where the interstitialDelegate is placed. I am trying to implement func interstitialDidDismissScreen(ad: GADInterstitial!) {} to trigger a change back to my game scene and nothing happens when I dismiss the ad.
I have tried placing it in override func didMove(to view: SKScene){} as well as when the restart button is pressed and still won't work. This is how i have the ad being called
fun loadAndShow() {
myAd = GADInterstitial()
let requestI = GADRequest()
myAd.setAdUnitID("adID")
requestI.testDevices = [kGADSimulatorID, "test device"]
myAd.delegate = self
myAd.load(requestI)
}
func interstitialDidReceiveAd(_ ad: GADInterstitial) {
if (self.myAd.isReady) {
myAd.present(fromRootViewController: self)
}
}
you can use delegate methods of admob so when interstitial is going to be shown you can remove the restart button or put a condition so that it would not work when ad is shown. Also to pause the game is also important if it is running using isPaused bool.
https://developers.google.com/admob/ios/ad-events

Does openParentApplication:reply require App Groups capability to be enabled?

I am developing an app that communicates between the watch and the iOS parent app. It sends data from the WatchKit extension to the parent application by opening it. I understand that openParentApplication:reply, when called, opens the iPhone application from the Apple Watch. After that, application:handleWatchKitExtension:reply is called in the app's delegate.
From there you can open a notification to the view controller with:
NSNotificationCenter.defaultCenter().postNotificationName(aName: String, object anObject: AnyObject?)
"aName" is what you can open up in the view conroller with:
NSNotificationCenter.defaultCenter().addObserver(self,
selector: Selector("handleWatchKitNotification:"),
name: "WatchKitSaysHello",
object: nil)
Here is my code for my interface controller in my WatchKit extension:
//
// InterfaceController.swift
// SendColors WatchKit Extension
//
// Created by Tommy on 12/30/14.
// Copyright (c) 2014 Tommy. All rights reserved.
//
import WatchKit
import Foundation
class InterfaceController: WKInterfaceController {
var ypo = false
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
// Configure interface objects here.
}
#IBOutlet weak var redButton: WKInterfaceButton!
#IBOutlet weak var greenButton: WKInterfaceButton!
#IBOutlet weak var blueButton: WKInterfaceButton!
#IBAction func onRedButtonClick() {
if ypo {
openParentAppWithColor("Yellow")
}
else {
openParentAppWithColor("Red")
}
}
#IBOutlet weak var moreButton: WKInterfaceButton!
#IBAction func moreButtonClick() {
if !ypo {
ypo = true
redButton.setTitle("Yellow")
redButton.setColor(UIColor.yellowColor())
greenButton.setTitle("Purple")
greenButton.setColor(UIColor.purpleColor())
blueButton.setTitle("Orange")
blueButton.setColor(UIColor.orangeColor())
moreButton.setTitle("Back")
}
else {
ypo = false
redButton.setTitle("Red")
redButton.setColor(UIColor.redColor())
greenButton.setTitle("Green")
greenButton.setColor(UIColor.greenColor())
blueButton.setTitle("Blue")
blueButton.setColor(UIColor.blueColor())
moreButton.setTitle("More...")
}
}
#IBAction func onGreenButtonClick() {
if ypo {
openParentAppWithColor("Purple")
}
else {
openParentAppWithColor("Green")
}
}
#IBAction func onBlueButtonClick() {
if ypo {
openParentAppWithColor("Orange")
}
else {
openParentAppWithColor("Blue")
}
}
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
}
override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
}
private func openParentAppWithColor(color: String) {
if ["color": color] != nil {
if !WKInterfaceController.openParentApplication(["color": color], reply: { (reply, error) -> Void in
println(reply)
}) {
println("ERROR")
}
}
}
}
My problem is that say for instance I clicked the red button on the watch simulator. The action would be called and in that action it calls openParentApplicationWithColor("Red") which would call WKInterfaceController.openParentApplication(["color": color], reply: { (reply, error) -> Void in }) What this is supposed to do is open the parent app on the simulator. It opens it in the background. I, therefore open it manually. When I open the app manually, the background is completely black. I suspect the problem is that I did not enable App Groups in the Capabilities tab. In order to do that, you need to be in the developer program. Should I join it to do this, or is there another problem? I am using Xcode 6.2 Beta 3. Thank you all in advance!
I have tested and can confirm that openParentApplication:reply: does not require App Groups to be enabled.
I understand that openParentApplication:reply, when called, opens the iPhone application from the Apple Watch.
This method opens the iPhone app in the background. In previous betas of Xcode 6.2 the app did open in the foreground, but this was not the intended behaviour and is not how the WatchKit Extension-iPhone app communication will work in the shipping version.
You can still launch the iPhone app in the foreground manually, but this isn't necessary unless you want to test the use case of both being used at once. At least with the API currently available, the iPhone app it can't be launched programmatically by the watch app to the foreground, and the watch app can't be launched programmatically by the iPhone app.
Once the app launches, you've reported the screen is still black when you expect it to change colour based on the message you've sent it. Is application:handleWatchKitExtension:reply: being called in the iPhone app? You will know it is definitely being called if you are receiving the reply block back for execution in your WatchKit Extension, which should be outputting something from your println(reply). If so, then the issue is with the code in the iPhone app to do something with the message you've passed to it. It would be useful to see your implementation of that method in your AppDelegate of the iPhone app. (Note if that method failed to call the reply block, it might still be receiving the message and you wouldn't get the reply, but then you would be seeing an error message about the reply not being received.)
Note that you won't see NSLog messages or get breakpoints in Xcode when running the Watch extension initially, but you can select Debug > Attach to process > [select your iPhone app under 'Likely targets'] and then you will get the logs and breakpoints of the iPhone app instead of the Watch app, while still being able to use the Watch app in the watch simulator. Most useful for debugging.
No, you no need to make group enable to use ole parent application. you can make a request to open parent IOS application and waiting a reply from IOS App without setting the group app. You only need to setting the group app when you want to share data between watchkit app and IOS app using NSUserDefauts with suite name.
I am using Xcode 6.2 Beta 5. Select Debug > Attach to process > [select your iPhone app under likely targets is not working. I see the NSLogs for Watch extension but not in iPhone app delegate and view controller of iPhone app.

ios iAd loading before displaying

I'm working on a iOS game in swift.
I'm trying to add an interstitial ad.
What I would like to do is when the game is over, displaying an Ad.
After closing it, the user can launch another game.
When the game is over I call this method:
func showFullScreenAd() {
if requestingAd == false {
interstitial = ADInterstitialAd()
interstitial!.delegate = self
requestingAd = true
}
}
func interstitialAdDidLoad(interstitialAd: ADInterstitialAd!) {
if interstitial?.loaded==true{
....}
}
The ad will be displayed when interstitialAdDidLoad is called.
So, between showFullScreenAd() and interstitialAdDidLoad some times we may have several seconds (the time for the ad to load) so the user can click on 'new game' and starts the game.
So, the game will begin and then the ad will be displayed (I'm handling the pause mode also) but it's weird to start the game and to have the ad showing up.
I'm thinking about the following case:
doing
interstitial = ADInterstitialAd()
when loading the game
and when the game is over just show the ad (if available), and doing it again after that.
What do you think about this ?
Thanks.
C.C.
You have to add the ad onto the view as a subview right? So load it and add it to the view when you are ready to. I'm assuming that you're doing it before interstitialAdDidLoad at the moment?

Resources