skip to Main Content

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:

enter image description here

enter image description here

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.

enter image description here

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


  1. Try to edit the XML of your Storyboard to fix this issue.

    • Right-click on your storyboard or interface builder.
    • Select view controller or view and go to Project Navigator panel and select the Open As->SourceCode menu choice.
    • add the attribute customClass="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.

    Login or Signup to reply.
  2. TL;DR

    Downgrade the CocoaPods pod version to 7.67.0. (-:

    Podfile

    pod 'Google-Mobile-Ads-SDK', '7.67.0'
    

    Explanation

    This is because GoogleMobileAds.framework became GoogleMobileAds.xcframework in 7.68.0+source. This means that the Objective C runtime differs between the framework (iOS 9) and the main target (iOS 14.0+). XCFrameworks 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 your Podfile 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 what GoogleUtilities does as well (a dependency of GoogleMobileAds) 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 to method 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 your Podfile for now. You can’t do anything else about this as an end-user of the framework, since the podspec specifies the framework type as a vendored_framework and this is only editable within the framework’s source code. I tried to disable use_frameworks but that doesn’t compile. If you can edit the podspec 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 disabling use_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.

    Login or Signup to reply.
  3. 1: pod install —clean-install

    2: open Xcode and shiftcommandk

    3: close Xcode and reopen

    4: take coffee and wait xcode prebuild complete

    Login or Signup to reply.
  4. 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 (or GADNativeAdView as GADUnifiedNativeAdView 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)

    GADUnifiedNativeAdView

    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.

    Outlet Collections not supported

    In this case, you can link the outlets by editing the view’s source code.

    1. Complete your Native Ad layout from the interface builder.
    2. From the Project Navigator panel, right-click the view (*.xib) file and select Open As > Source Code.
    3. Within the <view> tag for the GADUnifiedNativeAdView / 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 the destination 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):

    <?xml version="1.0" encoding="UTF-8"?>
    <document ...>
        <objects>
            <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="GADUnifiedNativeAdView">
                <subviews>
                    <view ... id="BAF-yb-wZL" userLabel="media" customClass="GADMediaView">
                        ...
                    </view>
                    <view ... id="U4D-Gx-1Wm" userLabel="bottom">
                        <subviews>
                            <imageView ... id="6hd-Ad-50f" userLabel="icon">
                                ...
                            </imageView>
                            <stackView ...>
                                <subviews>
                                    <label ... id="UdA-3o-ttn" userLabel="headline">
                                        ...
                                    </label>
                                    <label ... id="Dqe-NX-Uu2" userLabel="body">
                                        ...
                                    </label>
                                </subviews>
                            </stackView>
                        </subviews>
                    </view>
                </subviews>
                <!-- TODO: Add outlet connections -->
                <connections>
                    <outlet property="bodyView" destination="Dqe-NX-Uu2" id="GAD-Nat-Bdy"/>
                    <outlet property="headlineView" destination="UdA-3o-ttn" id="GAD-Nat-Hdl"/>
                    <outlet property="iconView" destination="6hd-Ad-50f" id="GAD-Nat-Ico"/>
                    <outlet property="mediaView" destination="BAF-yb-wZL" id="GAD-Nat-Mdv"/>
                </connections>
            </view>
        </objects>
    </document>
    

    Important: You need to generate an object ID for outlets similar to others (e.g., XXX-YYY-ZZZ), to avoid unexpected errors. I used GAD-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.

    Custom class dropdown

    Then, you’ll find the property name for the outlets from its header file. (GADUnifiedNativeAdView for example)

    GADUnifiedNativeAdView header

    Important: You need to build your project at least once to make your Xcode to find the header for your custom class.

    1. 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.

    2. 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.

    Connections inspector

    1. Load and display the ad.
    Login or Signup to reply.
  5. According to Google Developer in this link.

    We are aware of this issue — .xcframework is generally incompatible
    with .xib files. This is a Apple bug that we don’t know when it’ll get
    fixed.

    As a temporary workaround, you could make a manual copy of the
    GADNativeAdView.h file to include in your project. You should then see
    all the outlets appearing in Interface Builder as expected.

    I am successfully able to get the outlets following this workaround.

    Here’s what you need to do

    1. Copy the contents of the file GADNativeAd.h. You can open this file by setting the class of a view in IB as GADNativeAdView. Then click on the disclosure arrow to open the class. Make sure to change it back to whatever it was originally.

    enter image description here

    1. Now create a new file i.e header file. Name it GADNativeAd.h.

    2. Paste the contents of that file in this newly created file.

    3. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search