简体   繁体   English

Admob 框架 class 未被 Xcode 接口构建器检测到

[英]Admob Framework class not detected by Xcode interface builder

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 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. 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.但奇怪的是,在我的 swift 文件中导入框架后,我可以使用所有与 admob 相关的类。 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 ).我发现了一个 github 项目,它只是通过 Cocoapoding admob 框架实现了 admob 原生广告。(项目链接 I downloaded its source code and oddly the admob framework classes can be detected by interface face in this project.我下载了它的源代码,奇怪的是admob框架类在这个项目中可以通过接口面检测到。

在此处输入图像描述

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.如果您知道为什么会发生这种情况并且您的帮助受到高度赞赏,请帮助我。

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. TL;DR:对于那些无法将 SDK 降级到 7.68.0 以下的人,打开xib作为源代码并手动编辑代码以设置自定义 Class 并将插座链接到视图。

You can set the custom class to GADUnifiedNativeAdView (or GADNativeAdView as GADUnifiedNativeAdView is now deprecated) by typing the class name directly to the field.您可以通过在字段中直接键入 class 名称来将自定义 class 设置为GADUnifiedNativeAdView (或GADNativeAdView ,因为GADUnifiedNativeAdView现在已弃用)。

Note that you don't need to worry if the class name doesn't show up in the dropdown list.请注意,如果 class 名称未显示在下拉列表中,您无需担心。 You can just type it as you can see from the below screenshot.从下面的屏幕截图中可以看到,您只需键入它即可。 ( GADUnifiedNativeAdView for example) (例如GADUnifiedNativeAdView

GADUnifiedNativeAdView

However, you can't link outlets to views (eg, 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 链接到视图(例如,将您的视图链接到每个原生广告视图),因为您不会在GADUnifiedNativeAdView中看到 outlet,正如您从以下屏幕截图中看到的那样。

不支持奥特莱斯系列

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 .Project Navigator面板中,右键单击视图 ( *.xib ) 文件和 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.GADUnifiedNativeAdView / GADNativeAdView<view>标记中,添加<connections>标记并声明每个原生广告视图的出口。 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.请注意,您需要从destination标签中引用视图的 object ID,并自己为每个插座生成 object ID。

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 (eg, XXX-YYY-ZZZ ), to avoid unexpected errors.重要提示:您需要为与其他类似的插座(例如, XXX-YYY-ZZZ )生成 object ID,以避免意外错误。 I used GAD-Nat-XXX format in the above example.我在上面的例子中使用了GAD-Nat-XXX格式。

If you want to lookup the property name for each outlet, click the grey arrow button in the custom class dropdown.如果要查找每个插座的属性名称,请单击自定义 class 下拉列表中的灰色箭头按钮。

自定义类下拉列表

Then, you'll find the property name for the outlets from its header file.然后,您将从其 header 文件中找到插座的属性名称。 ( GADUnifiedNativeAdView for example) (例如GADUnifiedNativeAdView

GADUnifiedNativeAdView 标头

Important: You need to build your project at least once to make your Xcode to find the header for your custom class.重要提示:您需要至少构建一次项目以使您的 Xcode 为您的自定义 class 找到 header。

  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 .Project Navigator中,通过右键单击视图并选择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.您会看到一个警告图标,但您可以忽略它。

连接检查员

  1. Load and display the ad. 加载并显示广告。

Try to edit the XML of your Storyboard to fix this issue.尝试编辑 Storyboard 的 XML 以解决此问题。

  • Right-click on your storyboard or interface builder.右键单击 storyboard 或界面生成器。
  • Select view controller or view and go to Project Navigator panel and select the Open As->SourceCode menu choice. Select 查看 controller 或查看 go 到 Project Navigator 面板和 Z99938282-1816E 代码菜单选择。
  • add the attribute customClass=" GADUnifiedNativeAdvView "添加属性 customClass=" GADUnifiedNativeAdvView "

Save the storyboard or view.保存 storyboard 或查看。

Right-click your storyboard/view entry in the Project Navigator panel again, and select the Open As->Interface Builder再次右键单击 Project Navigator 面板中的情节提要/视图条目,然后 select Open As->Interface Builder

Hpefully, you will see the custom class name. Hpefully,您将看到自定义 class 名称。

TL;DR TL;博士

Downgrade the CocoaPods pod version to 7.67.0 .将 CocoaPods pod 版本降级到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 .这是因为GoogleMobileAds.frameworkGoogleMobileAds.xcframework中变成了7.68.0+ - source This means that the Objective C runtime differs between the framework (iOS 9) and the main target (iOS 14.0+).这意味着 Objective C 运行时在框架(iOS 9)和主要目标(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 your Podfile it won't make a difference. XCFramework是一种特殊类型的二进制框架,因此在 iOS 版本已经编译后手动编辑它不会有任何区别,事实上,即使您在Podfile中指定 iOS 版本也不会有任何区别.

The main code has a different, faster Objective-C runtime under the hood, and so tracks classes using different data structures to the XCFramework .主代码在底层有一个不同的、更快的 Objective-C 运行时,因此使用不同的数据结构跟踪类到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).例如,如果在框架中定义了一个类别,即使没有使用新的覆盖方法(在运行时),它也将存储在读写 memory 中。 On the other hand, the Objective-C runtime in iOS 14.0+ doesn't load these methods until they are used to save RAM.另一方面,iOS 14.0+ 中的 Objective-C 运行时在用于节省 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.这是旧 iOS 版本的重大更改,因为用于索引这些类的旧数据结构不再包括类别方法(在同一存储区域中),并且框架中的依赖逻辑(读取这些数据结构)将不再起作用。 Method swizzling is handled differently and this is what GoogleUtilities does as well (a dependency of GoogleMobileAds ) so this can cause issues.方法调配的处理方式不同,这也是GoogleUtilities所做的( GoogleMobileAds的依赖项),因此这可能会导致问题。 So even if IB Autocomplete doesn't work (no big issue there), the class won't be found dynamically at runtime.因此,即使 IB 自动完成功能不起作用(那里没有大问题),在运行时也不会动态找到 class。 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 ).我没有提到在新运行时对method list表示更改的更改,因为该问题超出了 scope 的范围,但旧方法列表在运行时仍然可用(非破坏性更改)。

To work around this, just use the 7.67.0 version in your Podfile for now.要解决这个问题,现在只需在Podfile中使用7.67.0版本。 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.作为框架的最终用户,您不能对此做任何其他事情,因为podspec将框架类型指定为vendored_framework并且只能在框架的源代码中进行编辑。 I tried to disable use_frameworks but that doesn't compile.我试图禁用use_frameworks但这没有编译。 If you can edit the podspec for your own frameworks, changing to a static framework is a viable solution (with caveats).如果您可以为自己的框架编辑podspec ,则更改为 static 框架是一个可行的解决方案(带有警告)。 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).该框架在构建时链接,而不是在 static 框架的加载时链接,因此您应该能够在 IB 中看到框架 class,但随后您必须使框架的依赖 pod 也为 ZA81259CEF8E959C624ZD1D456(更多工作)。 The easier equivalent is to just downgrade the pod, or disabling use_frameworks in the Podfile.更简单的等价物是降级 pod,或在 Podfile 中禁用use_frameworks However, frameworks have faster performance (linking time) and are generally preferred which is why they are enabled by default for CocoaPods.但是,框架具有更快的性能(链接时间)并且通常是首选的,这就是为什么它们默认为 CocoaPods 启用的原因。

I would also have suggested making a new GitHub Issue for this bug, but it looks like the SDK is not open-source.我还建议为此错误创建一个新的 GitHub 问题,但看起来 SDK 不是开源的。 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.也许这个错误将来会由 Apple 解决,或者一旦他们意识到它就会由 Google 解决,但目前这是一种解决方法

1: pod install —clean-install 1:吊舱安装——干净安装

2: open Xcode and shift - command - k 2:打开Xcode并shift - command - k

3: close Xcode and reopen 3:关闭 Xcode 并重新打开

4: take coffee and wait xcode prebuild complete 4:喝咖啡,等待 xcode 预构建完成

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM