I’ve been trying to implement native Google adMob ads in my iOS app and followed the admob official tutorial: https://developers.google.com/admob/ios/native/advanced
Whether I added the required admob framework manually or by CocoaPods, all the classes in the admob frameworks were not detected by the interface builder, so I could not set the Custom class of UIView to the wanted admob view classes. But weirdly I could use all the admob-related classes after the framework was imported in my swift files.
See the below screenshot:
I found a github project, which did nothing but just implmented the admob native ad by Cocoapoding the admob framework (project link). I downloaded its source code and oddly the admob framework classes can be detected by interface face in this project.
I’ve been scratching my heads for a couple days and searching for the solution without luck. Please help me out if you have a clue why this happened and your help is highly apprecaited.
5
Answers
Try to edit the XML of your Storyboard to fix this issue.
GADUnifiedNativeAdvView
"Save the storyboard or view.
Right-click your storyboard/view entry in the Project Navigator panel again, and select the Open As->Interface Builder
Hpefully, you will see the custom class name.
TL;DR
Downgrade the CocoaPods pod version to
7.67.0
. (-:Podfile
Explanation
This is because
GoogleMobileAds.framework
becameGoogleMobileAds.xcframework
in7.68.0+
– source. This means that the Objective C runtime differs between the framework (iOS 9) and the main target (iOS 14.0+).XCFramework
s are a special type of binary framework, so editing the iOS version manually after it has already been compiled won’t make a difference, and in fact, even if you specify an iOS version in yourPodfile
it won’t make a difference.The main code has a different, faster Objective-C runtime under the hood, and so tracks classes using different data structures to the
XCFramework
. For example, if a category is defined in the framework, that will be stored in read-write memory even if the new overridden method isn’t used (at runtime). On the other hand, the Objective-C runtime in iOS 14.0+ doesn’t load these methods until they are used to save RAM. This is a breaking change for old iOS versions because the old data structures used to index these classes no longer include the category methods (in the same storage area) and dependent logic (that reads these data structures) in the framework will no longer work. Method swizzling is handled differently and this is whatGoogleUtilities
does as well (a dependency ofGoogleMobileAds
) so this can cause issues. So even if IB Autocomplete doesn’t work (no big issue there), the class won’t be found dynamically at runtime. I haven’t mentioned changes tomethod list
representation changes under the hood in the new runtime since that is out of scope for this question, but old method lists will still be usable at runtime (non-breaking change).To work around this, just use the
7.67.0
version in yourPodfile
for now. You can’t do anything else about this as an end-user of the framework, since thepodspec
specifies the framework type as avendored_framework
and this is only editable within the framework’s source code. I tried to disableuse_frameworks
but that doesn’t compile. If you can edit thepodspec
for your own frameworks, changing to a static framework is a viable solution (with caveats). The framework get linked at build time instead of load time for static frameworks so you should be able to see the framework class in IB, but then you have to make the dependent pods of the framework also static (more work). The easier equivalent is to just downgrade the pod, or disablinguse_frameworks
in the Podfile. However, frameworks have faster performance (linking time) and are generally preferred which is why they are enabled by default for CocoaPods.I would also have suggested making a new GitHub Issue for this bug, but it looks like the SDK is not open-source. Maybe this bug will be resolved by Apple in the future, or by Google once they become aware of it but this is a workaround for now.
1: pod install —clean-install
2: open Xcode and shift–command–k
3: close Xcode and reopen
4: take coffee and wait xcode prebuild complete
TL;DR: For those who can’t downgrade the SDK below 7.68.0, open the
xib
as a source code and manually edit the code to set the Custom Class and to link outlets to views.You can set the custom class to
GADUnifiedNativeAdView
(orGADNativeAdView
asGADUnifiedNativeAdView
is now deprecated) by typing the class name directly to the field.Note that you don’t need to worry if the class name doesn’t show up in the dropdown list. You can just type it as you can see from the below screenshot. (
GADUnifiedNativeAdView
for example)However, you can’t link outlets to views (e.g., link your views to each native ad views) as you won’t see the outlets in the
GADUnifiedNativeAdView
as you can see from the following screenshot.In this case, you can link the outlets by editing the view’s source code.
*.xib
) file and select Open As > Source Code.<view>
tag for theGADUnifiedNativeAdView
/GADNativeAdView
, add the<connections>
tag and declare the outlet for each native ad views. Note that you need to reference your view’s object ID from thedestination
tag and generate an object ID for each outlet by yourself.Here’s an example that lays out four native ad assets (media, icon, headline and body):
Important: You need to generate an object ID for outlets similar to others (e.g.,
XXX-YYY-ZZZ
), to avoid unexpected errors. I usedGAD-Nat-XXX
format in the above example.If you want to lookup the property name for each outlet, click the grey arrow button in the custom class dropdown.
Then, you’ll find the property name for the outlets from its header file. (
GADUnifiedNativeAdView
for example)Important: You need to build your project at least once to make your Xcode to find the header for your custom class.
From the Project Navigator, Open the view file with the interface builder by right-clicking the view and selecting Open As > Interface Builder XIB Document.
From the connections inspector, confirm the connections that you added in the previous step. You’ll see a warning icon, but you can ignore it.
According to Google Developer in this link.
I am successfully able to get the outlets following this workaround.
Here’s what you need to do
GADNativeAd.h
. You can open this file by setting the class of a view in IB asGADNativeAdView
. Then click on the disclosure arrow to open the class. Make sure to change it back to whatever it was originally.Now create a new file i.e header file. Name it
GADNativeAd.h
.Paste the contents of that file in this newly created file.
Build the project once.
You should now be seeing the outlets in your xib’s Connection Inspector.
Refrain from falling back to a working version as iOS ATT changes won’t be present in them.