I have added Facebook audience network in my iOS App for native ads integration. Everything is working fine but there are only testing ads.
I have added testDeviceKey for displaying ads if I try to remove this then no ads are displaying that is also making me confused. My code is -
#implementation AdFeedsView
FBNativeAd *nativeAd;
static NSString *adPlacementId = #"xxxxxxxxx";
- (void)showNativeAd:(UIViewController *)vc
{
nativeAd = [[FBNativeAd alloc] initWithPlacementID:adPlacementId];
nativeAd.delegate = self;
NSLog(#"isTestMode1: %d",[FBAdSettings isTestMode]);
NSString *testDeviceKey = [FBAdSettings testDeviceHash];
if (testDeviceKey) {
[FBAdSettings addTestDevice:testDeviceKey];
}
[nativeAd loadAd];
}
So I just want to ask that what changes should I need to do in my code so that we can see proper ads other than testing ads in my live app?
Finally I find the solution. Actually I have added the code
NSString *testDeviceKey = [FBAdSettings testDeviceHash];
if (testDeviceKey) {
[FBAdSettings addTestDevice:testDeviceKey];
}
that is making all the active devices as testing devices hence there are only testing ads. I have removed it in the live version and included the code
[FBAdSettings clearTestDevices];
We can also do
if ([FBAdSettings isTestMode]) {
[FBAdSettings clearTestDevice:[FBAdSettings testDeviceHash]];
}
I have a wrong perception about testmode. I think that it will be false when my app become live but actually it just tell that the device has been added as testdevice or not.
Swift 3
This code will make sure that your test ads show on testflight or the simulator/device and also will make sure when you release to the app store that your ads will be shown as LIVE ads and the test devices will be cleared.
If you have your ads in many places you can put this code in the AppDelegate
import FBAudienceNetwork
private func facebookAdsControl() {
#if RELEASE
self.clearTestDevicesForFacebookAds()
#else
self.addTestDevicesForFacebookAds()
#endif
}
///remove for live mode
private func addTestDevicesForFacebookAds(){
let key = FBAdSettings.testDeviceHash()
FBAdSettings.setLogLevel(FBAdLogLevel.Log)
FBAdSettings.addTestDevice(key)
}
///add for live mode
private func clearTestDevicesForFacebookAds() {
FBAdSettings.clearTestDevices()
}
call the: facebookAdsControl() in the didFinishLaunchingWithOptions
You can also call this code in the code where you have the ads but make sure you call it before adView.load()
In order to use the macro you have to add the flags to your Swift Flags in the Build Settings
I hope this helps someone as the Facebook Docs are not very clear as I have found out.
Related
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
Is there any restriction that it is not possible to display a bannerview from Google Admob in a sharesheet? I have an app which provides additional data in the sharesheet, and I also want to display ads there. In my main app, the ads work fine - but in the sharesheet, I don't get any error message or anything when initialising the ads.
Greetings,
Jack
Update: I am using the cocoapod Firebase/Admob. This one is assigned to the main app and the sharesheet. As I have the ads on several view controlers, I created a function, which is connected via an app group to both parts. In ViewDidLoad, I initialice google admob
GADMobileAds.configure(withApplicationID: "filledwiththecorrectcode")
Then I run this function providing the view and the constrains:
func loadAdd(ViewController: GADBannerView, HightConstrain: NSLayoutConstraint, MainApp: Bool){
ViewController.adSize = kGADAdSizeSmartBannerPortrait
// TEST CODE
ViewController.adUnitID = "ca-app-pub-3940256099942544/2934735716"
ViewController.rootViewController = self
HightConstrain.constant = 50
let request: GADRequest = GADRequest()
request.testDevices = [kGADSimulatorID]
ViewController.load(request)
}
}
This works fine in the main app. In the sharesheet, I run the same function - it also walks through in the debugger, but nothing happens. Ah, the
I write SDK for iOS and I want to validate if StoreKit.framework is linked to application that uses my SDK, so I run:
if ([SKStoreProductViewController class]) {
SKStoreProductViewController *storeController =
[[ SKStoreProductViewController alloc ] init ];
// ...
}
However even if StoreKit.framework is not linked [SKStoreProductViewController class still returns true.
How to solve this problem?
Edit 1
as #x4h1d pointed I created new empty project and added to default Controller:
BOOL isStoreKitAvailable =
(NSClassFromString(#"SKStoreProductViewController") != nil);
// => YES (there is no linked frameworks at all, why I get YES?)
Edit 2
My Provisioning profile has In-App Purchase enabled (not a project itself)
from iOS App IDs:
However from Xcode:
Maybe this is a reason why even empty application has build-in StoreKit?
You can check the storekit availibility using following code.
func checkStoreKitAvailibility() -> Bool {
for bundle in Bundle.allFrameworks {
if ((bundle.classNamed("SKStoreProductViewController")) != nil) {
return true;
}
}
return false;
}
Edit:
For Objective-C you can use:
- (BOOL)checkStoreKitAvailibility {
for (NSBundle *bundle in NSBundle.allFrameworks) {
if ([bundle classNamed:#"SKStoreProductViewController"]) {
return YES;
}
}
return NO;
}
In the Linked Frameworks and Libraries make it Optional instead of Required. So, that if the application developers wants it to implement he will mark the framework as Required in the application. Now if you use the [SKStoreProductViewController class]. it may crash use the NSStringFromClass(#"SKStoreProductViewController") to determine if its safe to use it.
In Xcode,
when we enable the In-App purchase under Capabilities, Xcode automatically links StoreKit.framework and Add the In-App purchase feature to our App ID. Similarly if our App ID already have In-App purchase enabled the same happens.
So by doing simply,
BOOL isStoreKitAvailable = (NSClassFromString(#"SKStoreProductViewController") != nil);
I hope this might help you.
//SWIFT
class func allFrameworks() -> [AnyObject]
//OBJECTIVE-C
+ (NSArray *)allFrameworks
From NSBundle
+allFrameworks
Returns an array of all of the application’s bundles that represent frameworks.
Return Value
An array of all of the application’s bundles that represent frameworks. Only frameworks with one or more Objective-C classes in them are included.
Import Statement
import Foundation
Availability
Available in iOS 2.0 and later.
How to Use
(NSBundle.allFrameworks() -> Return Array of All framework use in project.
You can Check Using for loop apllication contain storeKit.framework or Not as Below.
Swift :---
func isStoreKitAvailable() -> Bool {
for frameWorkName in Bundle.allFrameworks {
if ((frameWorkName.classNamed("SKStoreProductViewController")) != nil) {
return true;
}
}
return false;
}
Objective C :---
- (BOOL)isStoreKitAvailable {
for (NSBundle *frameWorkName in NSBundle.allFrameworks) {
if ([frameWorkName classNamed:#"SKStoreProductViewController"]) {
return YES;
}
}
return NO;
}
Find more reference from here
I have an iOS app that makes some small network requests on app launch (resource updates, etc). If the user turns off cellular access for the app in iOS Settings, they get a prompt from iOS about network usage every time they launch. Is there a way to know programmatically that cellular data for this app has been disabled, so that I can disable the requests at startup?
So I found this on the apple dev forums from an Apple engineer (https://devforums.apple.com/message/1059332#1059332).
Another developer wrote in to DTS and thus I had a chance to
investigate this in depth. Alas, the news is much as I expected:
there is no supported way to detect that your app is in this state.
Nor is there a way to make a "no user interaction" network connection,
that is, request that the connection fail rather than present UI like
this. If these limitations are causing problems for your app, I
encourage you to file a bug describing your specific requirements.
https://developer.apple.com/bug-reporting/
So it looks like it is not possible to detect if cellular data for your app has been turned off.
Edit
I filed a radar for this requesting that it be added. I just got this notification in my radar
We believe this issue has been addressed in the latest iOS 9 beta.
I looked through the API diffs, but so far I can't find the new API.
As of iOS9, the capability to check the setting to enable/disable use of cellular data for your app (Settings/Cellular/AppName) is available using Apple's CTCellularData class. The following code will set cellularDataRestrictedState when it is run initially and then set it and log whenever it changes:
import CoreTelephony
var cellularDataRestrictedState = CTCellularDataRestrictedState.restrictedStateUnknown
let cellState = CTCellularData.init()
cellState.cellularDataRestrictionDidUpdateNotifier = { (dataRestrictedState) in
if cellularDataRestrictedState != .restrictedStateUnknown { // State has changed - log to console
print("cellularDataRestrictedState: " + "\(dataRestrictedState == .restrictedStateUnknown ? "unknown" : dataRestrictedState == .restricted ? "restricted" : "not restricted")")
}
cellularDataRestrictedState = dataRestrictedState
}
Unfortunately (as of iOS11) this seems to check only the state of the app's switch - if your app's switch is set to enabled and the user switches the Cellular Data master switch to disabled, this API will return the app's state as being "not restricted".
Just wanted to add an Objective C version of the above Swift code for future travellers.
- (void)monitorCanUseCellularData {
if (GCIsiOS9) {
CTCellularData *cellularData = [[CTCellularData alloc] init];
NSLog(#"%ld", cellularData.restrictedState);
// 0, kCTCellularDataRestrictedStateUnknown
[cellularData setCellularDataRestrictionDidUpdateNotifier:^(CTCellularDataRestrictedState state) {
NSLog(#"%ld", state);
self.canUseCellularData = cellularData.restrictedState ==2?true:false;
}];
}
}
I have found that the CTCellularData class needs some time to get to the correct value. In my implementation I call the didUpdateNotifier very early after appDidFinishLaunching. By the time my networking call are returning with errors I definitely have a correct value for the restricted state.
class CellularRestriction: NSObject {
private static var cellularData = CTCellularData()
private static var currentState = CTCellularDataRestrictedState.restrictedStateUnknown
static var isRestricted: Bool {
currentState = cellularData.restrictedState
return currentState == .restricted
}
static func prepare() {
if currentState == .restrictedStateUnknown {
cellularData.cellularDataRestrictionDidUpdateNotifier = { state in
currentState = cellularData.restrictedState // This value may be inconsistent, however the next read of isRestricted should be correct.
}
}
}
}
You can detect if cellular data disabled using NWPathMonitor class. (https://developer.apple.com/documentation/network/nwpathmonitor)
let cellMonitor = NWPathMonitor(requiredInterfaceType: .cellular)
cellMonitor.pathUpdateHandler = { path in
self.isCellConnected = path.status == .satisfied
}
Adding to dirkgroten's answer, you can use the Apple Reachability class, found here:
https://developer.apple.com/Library/ios/samplecode/Reachability/Introduction/Intro.html
It uses SCNetworkReachability, and is very straight forward to use, it will detect connectivity via Cell and WiFi as you will need to check both at start up.
There are lots of frameworks out there that will give you the status of your network connectivity, and of course you can roll your own. I've found AFNetworking to be one of the best. It has a singleton class called AFNetworkReachabilityManager that abstracts some of the complexities for you. Specifically you'll want to look at the two boolean properties:
reachableViaWWAN
reachableViaWiFi
There is also a reachability changed status block that you can set:
– setReachabilityStatusChangeBlock:
AFNetworking Github
AFNetworkReachabilityManager
Is there a way to determine which network a specific ad is from when using AdMob Mediation? For example, within the interstitialDidReceiveAd:(GADInterstitial *)ad method, does the variable ad have a specific property that contains the name of the ad network that the ad is from? I want to use the specific ad network to manipulate how my app works in terms of how to properly dismiss the view.
On Android you can do something like this:
adView.setAdListener(new AdListener() {
#Override
public void onAdLoaded() {
super.onAdLoaded();
Log.i("TEST", "onAdLoaded: " + adView.getMediationAdapterClassName());
}
});
Which will return something like:
I/TEST: onAdLoaded: com.mobfox.adapter.MobFoxAdapter
I'm using Xamarin.iOS so the following is in C#, but maybe it'll help you. I've used this code to determine whether the ad is from iAd or from AdMob. I wrote this quickly just for debugging purposes and this method will only tell you if the ad is from AdMob or something else, which in my case was always iAd.
var property = view.MediatedAdView.GetType().GetProperty("AdUnitID");
string adType;
if (property != null && property.GetValue(view.MediatedAdView) != null)
{
adType = "AdMob";
}
else
{
adType = "iAd";
}
Unfortunately the answer is no.
You can use ad.adNetworkClassName.
Example values I'm getting GADMAdapterGoogleAdMobAds, GADMAdapterUnity.
Works for both interstitial and rewarded video ads.
You can check the actual class being used in the delegate. The code in Swift:
func interstitialDidReceiveAd(_ interstitial: GADInterstitial) {
print("Interstitial adapter class name: \(interstitial.responseInfo.adNetworkClassName)")
}