├── .gitignore
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── Demo
├── AdmobSwitUIDemo.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── swiftpm
│ │ │ └── Package.resolved
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── AdmobSwitUIDemo.xcscheme
└── AdmobSwitUIDemo
│ ├── AdmobSwitUIDemo.entitlements
│ ├── AdmobSwitUIDemoApp.swift
│ ├── Assets.xcassets
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
│ ├── ContentView.swift
│ ├── Info-demo.plist
│ ├── Info-demo2.plist
│ └── Preview Content
│ └── Preview Assets.xcassets
│ └── Contents.json
├── Package.resolved
├── Package.swift
├── README.md
├── Sources
└── AdmobSwiftUI
│ ├── AdmobSwiftUI.swift
│ ├── Banner
│ ├── BannerView.swift
│ └── BannerViewController.swift
│ ├── Extensions
│ └── UIColor+Extensions.swift
│ ├── Fullscreen
│ ├── AdViewControllerRepresentable.swift
│ ├── InterstitialAdCoordinator.swift
│ └── RewardedAdCoordinator.swift
│ ├── Native
│ ├── NativeAdBannerView.swift
│ ├── NativeAdCardView.swift
│ ├── NativeAdView.swift
│ ├── NativeAdViewModel.swift
│ ├── NativeAdViewStyle.swift
│ └── NativeLargeAdBannerView.swift
│ └── Resources
│ ├── Assets.xcassets
│ ├── Contents.json
│ ├── stars_3_5.imageset
│ │ ├── Contents.json
│ │ └── stars_3_5.png
│ ├── stars_4.imageset
│ │ ├── Contents.json
│ │ └── stars_4.png
│ ├── stars_4_5.imageset
│ │ ├── Contents.json
│ │ └── stars_4_5.png
│ └── stars_5.imageset
│ │ ├── Contents.json
│ │ └── stars_5.png
│ ├── Info-demo.plist
│ ├── Localizable.xcstrings
│ └── NativeXibs
│ ├── NativeAdView.xib
│ └── NativeAdViewDemo.xib
└── Tests
└── AdmobSwiftUITests
└── AdmobSwiftUITests.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 | xcuserdata/
6 | DerivedData/
7 | .swiftpm/config/registries.json
8 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
9 | .netrc
10 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Demo/AdmobSwitUIDemo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 60;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1C415EE62A37D10A00D03783 /* AdmobSwitUIDemoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C415EE52A37D10A00D03783 /* AdmobSwitUIDemoApp.swift */; };
11 | 1C415EE82A37D10A00D03783 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C415EE72A37D10A00D03783 /* ContentView.swift */; };
12 | 1C415EEA2A37D10B00D03783 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1C415EE92A37D10B00D03783 /* Assets.xcassets */; };
13 | 1C415EEE2A37D10B00D03783 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1C415EED2A37D10B00D03783 /* Preview Assets.xcassets */; };
14 | 1CFF1F812BA5F29A00BD8164 /* AdmobSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = 1CFF1F802BA5F29A00BD8164 /* AdmobSwiftUI */; };
15 | /* End PBXBuildFile section */
16 |
17 | /* Begin PBXFileReference section */
18 | 1C415EE22A37D10A00D03783 /* AdmobSwitUIDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AdmobSwitUIDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
19 | 1C415EE52A37D10A00D03783 /* AdmobSwitUIDemoApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdmobSwitUIDemoApp.swift; sourceTree = ""; };
20 | 1C415EE72A37D10A00D03783 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
21 | 1C415EE92A37D10B00D03783 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
22 | 1C415EEB2A37D10B00D03783 /* AdmobSwitUIDemo.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AdmobSwitUIDemo.entitlements; sourceTree = ""; };
23 | 1C415EED2A37D10B00D03783 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
24 | 1C415EFC2A37D5EA00D03783 /* Info-demo.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-demo.plist"; sourceTree = ""; };
25 | /* End PBXFileReference section */
26 |
27 | /* Begin PBXFrameworksBuildPhase section */
28 | 1C415EDF2A37D10A00D03783 /* Frameworks */ = {
29 | isa = PBXFrameworksBuildPhase;
30 | buildActionMask = 2147483647;
31 | files = (
32 | 1CFF1F812BA5F29A00BD8164 /* AdmobSwiftUI in Frameworks */,
33 | );
34 | runOnlyForDeploymentPostprocessing = 0;
35 | };
36 | /* End PBXFrameworksBuildPhase section */
37 |
38 | /* Begin PBXGroup section */
39 | 1C415ED92A37D10A00D03783 = {
40 | isa = PBXGroup;
41 | children = (
42 | 1C415EE42A37D10A00D03783 /* AdmobSwitUIDemo */,
43 | 1C415EE32A37D10A00D03783 /* Products */,
44 | 1C415EF42A37D1A300D03783 /* Frameworks */,
45 | );
46 | sourceTree = "";
47 | };
48 | 1C415EE32A37D10A00D03783 /* Products */ = {
49 | isa = PBXGroup;
50 | children = (
51 | 1C415EE22A37D10A00D03783 /* AdmobSwitUIDemo.app */,
52 | );
53 | name = Products;
54 | sourceTree = "";
55 | };
56 | 1C415EE42A37D10A00D03783 /* AdmobSwitUIDemo */ = {
57 | isa = PBXGroup;
58 | children = (
59 | 1C415EE52A37D10A00D03783 /* AdmobSwitUIDemoApp.swift */,
60 | 1C415EE72A37D10A00D03783 /* ContentView.swift */,
61 | 1C415EE92A37D10B00D03783 /* Assets.xcassets */,
62 | 1C415EEB2A37D10B00D03783 /* AdmobSwitUIDemo.entitlements */,
63 | 1C415EEC2A37D10B00D03783 /* Preview Content */,
64 | 1C415EFC2A37D5EA00D03783 /* Info-demo.plist */,
65 | );
66 | path = AdmobSwitUIDemo;
67 | sourceTree = "";
68 | };
69 | 1C415EEC2A37D10B00D03783 /* Preview Content */ = {
70 | isa = PBXGroup;
71 | children = (
72 | 1C415EED2A37D10B00D03783 /* Preview Assets.xcassets */,
73 | );
74 | path = "Preview Content";
75 | sourceTree = "";
76 | };
77 | 1C415EF42A37D1A300D03783 /* Frameworks */ = {
78 | isa = PBXGroup;
79 | children = (
80 | );
81 | name = Frameworks;
82 | sourceTree = "";
83 | };
84 | /* End PBXGroup section */
85 |
86 | /* Begin PBXNativeTarget section */
87 | 1C415EE12A37D10A00D03783 /* AdmobSwitUIDemo */ = {
88 | isa = PBXNativeTarget;
89 | buildConfigurationList = 1C415EF12A37D10B00D03783 /* Build configuration list for PBXNativeTarget "AdmobSwitUIDemo" */;
90 | buildPhases = (
91 | 1C415EDE2A37D10A00D03783 /* Sources */,
92 | 1C415EDF2A37D10A00D03783 /* Frameworks */,
93 | 1C415EE02A37D10A00D03783 /* Resources */,
94 | );
95 | buildRules = (
96 | );
97 | dependencies = (
98 | );
99 | name = AdmobSwitUIDemo;
100 | packageProductDependencies = (
101 | 1CFF1F802BA5F29A00BD8164 /* AdmobSwiftUI */,
102 | );
103 | productName = AdmobSwitUIDemo;
104 | productReference = 1C415EE22A37D10A00D03783 /* AdmobSwitUIDemo.app */;
105 | productType = "com.apple.product-type.application";
106 | };
107 | /* End PBXNativeTarget section */
108 |
109 | /* Begin PBXProject section */
110 | 1C415EDA2A37D10A00D03783 /* Project object */ = {
111 | isa = PBXProject;
112 | attributes = {
113 | BuildIndependentTargetsInParallel = 1;
114 | LastSwiftUpdateCheck = 1430;
115 | LastUpgradeCheck = 1510;
116 | TargetAttributes = {
117 | 1C415EE12A37D10A00D03783 = {
118 | CreatedOnToolsVersion = 14.3;
119 | };
120 | };
121 | };
122 | buildConfigurationList = 1C415EDD2A37D10A00D03783 /* Build configuration list for PBXProject "AdmobSwitUIDemo" */;
123 | compatibilityVersion = "Xcode 14.0";
124 | developmentRegion = en;
125 | hasScannedForEncodings = 0;
126 | knownRegions = (
127 | en,
128 | Base,
129 | );
130 | mainGroup = 1C415ED92A37D10A00D03783;
131 | packageReferences = (
132 | 1CFF1F7F2BA5F29A00BD8164 /* XCLocalSwiftPackageReference ".." */,
133 | );
134 | productRefGroup = 1C415EE32A37D10A00D03783 /* Products */;
135 | projectDirPath = "";
136 | projectRoot = "";
137 | targets = (
138 | 1C415EE12A37D10A00D03783 /* AdmobSwitUIDemo */,
139 | );
140 | };
141 | /* End PBXProject section */
142 |
143 | /* Begin PBXResourcesBuildPhase section */
144 | 1C415EE02A37D10A00D03783 /* Resources */ = {
145 | isa = PBXResourcesBuildPhase;
146 | buildActionMask = 2147483647;
147 | files = (
148 | 1C415EEE2A37D10B00D03783 /* Preview Assets.xcassets in Resources */,
149 | 1C415EEA2A37D10B00D03783 /* Assets.xcassets in Resources */,
150 | );
151 | runOnlyForDeploymentPostprocessing = 0;
152 | };
153 | /* End PBXResourcesBuildPhase section */
154 |
155 | /* Begin PBXSourcesBuildPhase section */
156 | 1C415EDE2A37D10A00D03783 /* Sources */ = {
157 | isa = PBXSourcesBuildPhase;
158 | buildActionMask = 2147483647;
159 | files = (
160 | 1C415EE82A37D10A00D03783 /* ContentView.swift in Sources */,
161 | 1C415EE62A37D10A00D03783 /* AdmobSwitUIDemoApp.swift in Sources */,
162 | );
163 | runOnlyForDeploymentPostprocessing = 0;
164 | };
165 | /* End PBXSourcesBuildPhase section */
166 |
167 | /* Begin XCBuildConfiguration section */
168 | 1C415EEF2A37D10B00D03783 /* Debug */ = {
169 | isa = XCBuildConfiguration;
170 | buildSettings = {
171 | ALWAYS_SEARCH_USER_PATHS = NO;
172 | CLANG_ANALYZER_NONNULL = YES;
173 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
174 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
175 | CLANG_ENABLE_MODULES = YES;
176 | CLANG_ENABLE_OBJC_ARC = YES;
177 | CLANG_ENABLE_OBJC_WEAK = YES;
178 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
179 | CLANG_WARN_BOOL_CONVERSION = YES;
180 | CLANG_WARN_COMMA = YES;
181 | CLANG_WARN_CONSTANT_CONVERSION = YES;
182 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
183 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
184 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
185 | CLANG_WARN_EMPTY_BODY = YES;
186 | CLANG_WARN_ENUM_CONVERSION = YES;
187 | CLANG_WARN_INFINITE_RECURSION = YES;
188 | CLANG_WARN_INT_CONVERSION = YES;
189 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
190 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
191 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
192 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
193 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
194 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
195 | CLANG_WARN_STRICT_PROTOTYPES = YES;
196 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
197 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
198 | CLANG_WARN_UNREACHABLE_CODE = YES;
199 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
200 | COPY_PHASE_STRIP = NO;
201 | DEAD_CODE_STRIPPING = YES;
202 | DEBUG_INFORMATION_FORMAT = dwarf;
203 | ENABLE_STRICT_OBJC_MSGSEND = YES;
204 | ENABLE_TESTABILITY = YES;
205 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
206 | GCC_C_LANGUAGE_STANDARD = gnu11;
207 | GCC_DYNAMIC_NO_PIC = NO;
208 | GCC_NO_COMMON_BLOCKS = YES;
209 | GCC_OPTIMIZATION_LEVEL = 0;
210 | GCC_PREPROCESSOR_DEFINITIONS = (
211 | "DEBUG=1",
212 | "$(inherited)",
213 | );
214 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
215 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
216 | GCC_WARN_UNDECLARED_SELECTOR = YES;
217 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
218 | GCC_WARN_UNUSED_FUNCTION = YES;
219 | GCC_WARN_UNUSED_VARIABLE = YES;
220 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
221 | MTL_FAST_MATH = YES;
222 | ONLY_ACTIVE_ARCH = YES;
223 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
224 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
225 | };
226 | name = Debug;
227 | };
228 | 1C415EF02A37D10B00D03783 /* Release */ = {
229 | isa = XCBuildConfiguration;
230 | buildSettings = {
231 | ALWAYS_SEARCH_USER_PATHS = NO;
232 | CLANG_ANALYZER_NONNULL = YES;
233 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
234 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
235 | CLANG_ENABLE_MODULES = YES;
236 | CLANG_ENABLE_OBJC_ARC = YES;
237 | CLANG_ENABLE_OBJC_WEAK = YES;
238 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
239 | CLANG_WARN_BOOL_CONVERSION = YES;
240 | CLANG_WARN_COMMA = YES;
241 | CLANG_WARN_CONSTANT_CONVERSION = YES;
242 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
243 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
244 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
245 | CLANG_WARN_EMPTY_BODY = YES;
246 | CLANG_WARN_ENUM_CONVERSION = YES;
247 | CLANG_WARN_INFINITE_RECURSION = YES;
248 | CLANG_WARN_INT_CONVERSION = YES;
249 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
250 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
251 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
252 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
253 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
254 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
255 | CLANG_WARN_STRICT_PROTOTYPES = YES;
256 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
257 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
258 | CLANG_WARN_UNREACHABLE_CODE = YES;
259 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
260 | COPY_PHASE_STRIP = NO;
261 | DEAD_CODE_STRIPPING = YES;
262 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
263 | ENABLE_NS_ASSERTIONS = NO;
264 | ENABLE_STRICT_OBJC_MSGSEND = YES;
265 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
266 | GCC_C_LANGUAGE_STANDARD = gnu11;
267 | GCC_NO_COMMON_BLOCKS = YES;
268 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
269 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
270 | GCC_WARN_UNDECLARED_SELECTOR = YES;
271 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
272 | GCC_WARN_UNUSED_FUNCTION = YES;
273 | GCC_WARN_UNUSED_VARIABLE = YES;
274 | MTL_ENABLE_DEBUG_INFO = NO;
275 | MTL_FAST_MATH = YES;
276 | SWIFT_COMPILATION_MODE = wholemodule;
277 | SWIFT_OPTIMIZATION_LEVEL = "-O";
278 | };
279 | name = Release;
280 | };
281 | 1C415EF22A37D10B00D03783 /* Debug */ = {
282 | isa = XCBuildConfiguration;
283 | buildSettings = {
284 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
285 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
286 | CODE_SIGN_ENTITLEMENTS = AdmobSwitUIDemo/AdmobSwitUIDemo.entitlements;
287 | CODE_SIGN_STYLE = Automatic;
288 | CURRENT_PROJECT_VERSION = 1;
289 | DEAD_CODE_STRIPPING = YES;
290 | DEVELOPMENT_ASSET_PATHS = "\"AdmobSwitUIDemo/Preview Content\"";
291 | DEVELOPMENT_TEAM = M7K8VSF986;
292 | ENABLE_HARDENED_RUNTIME = YES;
293 | ENABLE_PREVIEWS = YES;
294 | GENERATE_INFOPLIST_FILE = YES;
295 | INFOPLIST_FILE = "AdmobSwitUIDemo/Info-demo.plist";
296 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
297 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
298 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
299 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES;
300 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES;
301 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES;
302 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault;
303 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
304 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
305 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
306 | IPHONEOS_DEPLOYMENT_TARGET = 16.4;
307 | LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
308 | "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
309 | MACOSX_DEPLOYMENT_TARGET = 13.1;
310 | MARKETING_VERSION = 1.0;
311 | OTHER_LDFLAGS = "-ObjC";
312 | PRODUCT_BUNDLE_IDENTIFIER = com.dearhui.AdmobSwitUIDemo;
313 | PRODUCT_NAME = "$(TARGET_NAME)";
314 | SDKROOT = auto;
315 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
316 | SUPPORTS_MACCATALYST = NO;
317 | SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
318 | SWIFT_EMIT_LOC_STRINGS = YES;
319 | SWIFT_VERSION = 5.0;
320 | TARGETED_DEVICE_FAMILY = "1,2";
321 | };
322 | name = Debug;
323 | };
324 | 1C415EF32A37D10B00D03783 /* Release */ = {
325 | isa = XCBuildConfiguration;
326 | buildSettings = {
327 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
328 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
329 | CODE_SIGN_ENTITLEMENTS = AdmobSwitUIDemo/AdmobSwitUIDemo.entitlements;
330 | CODE_SIGN_STYLE = Automatic;
331 | CURRENT_PROJECT_VERSION = 1;
332 | DEAD_CODE_STRIPPING = YES;
333 | DEVELOPMENT_ASSET_PATHS = "\"AdmobSwitUIDemo/Preview Content\"";
334 | DEVELOPMENT_TEAM = M7K8VSF986;
335 | ENABLE_HARDENED_RUNTIME = YES;
336 | ENABLE_PREVIEWS = YES;
337 | GENERATE_INFOPLIST_FILE = YES;
338 | INFOPLIST_FILE = "AdmobSwitUIDemo/Info-demo.plist";
339 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
340 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
341 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
342 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES;
343 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES;
344 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES;
345 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault;
346 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
347 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
348 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
349 | IPHONEOS_DEPLOYMENT_TARGET = 16.4;
350 | LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
351 | "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
352 | MACOSX_DEPLOYMENT_TARGET = 13.1;
353 | MARKETING_VERSION = 1.0;
354 | OTHER_LDFLAGS = "-ObjC";
355 | PRODUCT_BUNDLE_IDENTIFIER = com.dearhui.AdmobSwitUIDemo;
356 | PRODUCT_NAME = "$(TARGET_NAME)";
357 | SDKROOT = auto;
358 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
359 | SUPPORTS_MACCATALYST = NO;
360 | SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
361 | SWIFT_EMIT_LOC_STRINGS = YES;
362 | SWIFT_VERSION = 5.0;
363 | TARGETED_DEVICE_FAMILY = "1,2";
364 | };
365 | name = Release;
366 | };
367 | /* End XCBuildConfiguration section */
368 |
369 | /* Begin XCConfigurationList section */
370 | 1C415EDD2A37D10A00D03783 /* Build configuration list for PBXProject "AdmobSwitUIDemo" */ = {
371 | isa = XCConfigurationList;
372 | buildConfigurations = (
373 | 1C415EEF2A37D10B00D03783 /* Debug */,
374 | 1C415EF02A37D10B00D03783 /* Release */,
375 | );
376 | defaultConfigurationIsVisible = 0;
377 | defaultConfigurationName = Release;
378 | };
379 | 1C415EF12A37D10B00D03783 /* Build configuration list for PBXNativeTarget "AdmobSwitUIDemo" */ = {
380 | isa = XCConfigurationList;
381 | buildConfigurations = (
382 | 1C415EF22A37D10B00D03783 /* Debug */,
383 | 1C415EF32A37D10B00D03783 /* Release */,
384 | );
385 | defaultConfigurationIsVisible = 0;
386 | defaultConfigurationName = Release;
387 | };
388 | /* End XCConfigurationList section */
389 |
390 | /* Begin XCLocalSwiftPackageReference section */
391 | 1CFF1F7F2BA5F29A00BD8164 /* XCLocalSwiftPackageReference ".." */ = {
392 | isa = XCLocalSwiftPackageReference;
393 | relativePath = ..;
394 | };
395 | /* End XCLocalSwiftPackageReference section */
396 |
397 | /* Begin XCSwiftPackageProductDependency section */
398 | 1CFF1F802BA5F29A00BD8164 /* AdmobSwiftUI */ = {
399 | isa = XCSwiftPackageProductDependency;
400 | productName = AdmobSwiftUI;
401 | };
402 | /* End XCSwiftPackageProductDependency section */
403 | };
404 | rootObject = 1C415EDA2A37D10A00D03783 /* Project object */;
405 | }
406 |
--------------------------------------------------------------------------------
/Demo/AdmobSwitUIDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Demo/AdmobSwitUIDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Demo/AdmobSwitUIDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "originHash" : "47444872f92492e90ce4c162a2f7728300d081aa0ebc608437c2fcab58789f5a",
3 | "pins" : [
4 | {
5 | "identity" : "lbtatools",
6 | "kind" : "remoteSourceControl",
7 | "location" : "https://github.com/bhlvoong/LBTATools",
8 | "state" : {
9 | "revision" : "dce147bfbdc0417a4b430ec220c088629e9dc81d",
10 | "version" : "1.0.17"
11 | }
12 | },
13 | {
14 | "identity" : "swift-package-manager-google-mobile-ads",
15 | "kind" : "remoteSourceControl",
16 | "location" : "https://github.com/googleads/swift-package-manager-google-mobile-ads.git",
17 | "state" : {
18 | "revision" : "5ff977255c2ba5844e7e9da779f1f2a5a00e0028",
19 | "version" : "11.2.0"
20 | }
21 | },
22 | {
23 | "identity" : "swift-package-manager-google-user-messaging-platform",
24 | "kind" : "remoteSourceControl",
25 | "location" : "https://github.com/googleads/swift-package-manager-google-user-messaging-platform.git",
26 | "state" : {
27 | "revision" : "cfe8b2ae16b9bc81f4cdf1d1a12a01a452489c32",
28 | "version" : "2.3.0"
29 | }
30 | }
31 | ],
32 | "version" : 3
33 | }
34 |
--------------------------------------------------------------------------------
/Demo/AdmobSwitUIDemo.xcodeproj/xcshareddata/xcschemes/AdmobSwitUIDemo.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
42 |
44 |
50 |
51 |
52 |
53 |
59 |
61 |
67 |
68 |
69 |
70 |
72 |
73 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/Demo/AdmobSwitUIDemo/AdmobSwitUIDemo.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-only
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Demo/AdmobSwitUIDemo/AdmobSwitUIDemoApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AdmobSwitUIDemoApp.swift
3 | // AdmobSwitUIDemo
4 | //
5 | // Created by minghui on 2023/6/13.
6 | //
7 |
8 | import SwiftUI
9 | import GoogleMobileAds
10 |
11 | @main
12 | struct AdmobSwitUIDemoApp: App {
13 |
14 | init() {
15 | GADMobileAds.sharedInstance().start(completionHandler: nil)
16 | }
17 |
18 | var body: some Scene {
19 | WindowGroup {
20 | ContentView()
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Demo/AdmobSwitUIDemo/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Demo/AdmobSwitUIDemo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "platform" : "ios",
6 | "size" : "1024x1024"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "scale" : "1x",
11 | "size" : "16x16"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "scale" : "2x",
16 | "size" : "16x16"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "scale" : "1x",
21 | "size" : "32x32"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "scale" : "2x",
26 | "size" : "32x32"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "scale" : "1x",
31 | "size" : "128x128"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "scale" : "2x",
36 | "size" : "128x128"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "scale" : "1x",
41 | "size" : "256x256"
42 | },
43 | {
44 | "idiom" : "mac",
45 | "scale" : "2x",
46 | "size" : "256x256"
47 | },
48 | {
49 | "idiom" : "mac",
50 | "scale" : "1x",
51 | "size" : "512x512"
52 | },
53 | {
54 | "idiom" : "mac",
55 | "scale" : "2x",
56 | "size" : "512x512"
57 | }
58 | ],
59 | "info" : {
60 | "author" : "xcode",
61 | "version" : 1
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Demo/AdmobSwitUIDemo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Demo/AdmobSwitUIDemo/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // AdmobSwitUIDemo
4 | //
5 | // Created by minghui on 2023/6/13.
6 | //
7 |
8 | import SwiftUI
9 | import AdmobSwiftUI
10 |
11 | struct ContentView: View {
12 | @StateObject private var nativeViewModel = NativeAdViewModel(requestInterval: 1)
13 | private let adViewControllerRepresentable = AdViewControllerRepresentable()
14 | private let adCoordinator = InterstitialAdCoordinator()
15 | private let rewardCoordinator = RewardedAdCoordinator()
16 |
17 | @State private var hiddenNative = false
18 |
19 | var body: some View {
20 | ScrollView {
21 | VStack (spacing: 20) {
22 | Button("Show InterstitialAd") {
23 | Task {
24 | do {
25 | let ad = try await adCoordinator.loadAppOpenAd()
26 | ad.present(fromRootViewController: adViewControllerRepresentable.viewController)
27 | } catch {
28 | print(error.localizedDescription)
29 | }
30 | }
31 | }
32 |
33 | Button("show reward") {
34 | Task {
35 | do {
36 | let reward = try await rewardCoordinator.loadInterstitialAd()
37 | reward.present(fromRootViewController: adViewControllerRepresentable.viewController) {
38 | print("Reward amount: \(reward.adReward.amount)")
39 | }
40 | } catch {
41 | print(error.localizedDescription)
42 | }
43 | }
44 | }
45 |
46 | Button("reload native") {
47 | nativeViewModel.refreshAd()
48 | }
49 |
50 | Button("hidden native") {
51 | hiddenNative.toggle()
52 | }
53 |
54 | BannerView()
55 | .frame(height: 50)
56 | .background(Color.red)
57 |
58 | if !hiddenNative {
59 | NativeAdView(nativeViewModel: nativeViewModel, style: .banner)
60 | .frame(height: 80)
61 | .background(Color(UIColor.secondarySystemBackground))
62 |
63 | // NativeAdView(nativeViewModel: nativeViewModel, style: .card)
64 | // .frame(height: 380) // 250 ~ 300
65 | // .background(Color(UIColor.secondarySystemBackground))
66 | }
67 |
68 |
69 |
70 | }
71 | .padding()
72 | }
73 | .background {
74 | // Add the adViewControllerRepresentable to the background so it
75 | // doesn't influence the placement of other views in the view hierarchy.
76 | adViewControllerRepresentable
77 | .frame(width: .zero, height: .zero)
78 | }
79 | .onAppear {
80 | nativeViewModel.refreshAd()
81 | }
82 | }
83 | }
84 |
85 | struct ContentView_Previews: PreviewProvider {
86 | static var previews: some View {
87 | ContentView()
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/Demo/AdmobSwitUIDemo/Info-demo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSUserTrackingUsageDescription
6 | Your data will be used to deliver personalized ads to you.
7 | GADApplicationIdentifier
8 | ca-app-pub-3940256099942544~1458002511
9 | SKAdNetworkItems
10 |
11 |
12 | SKAdNetworkIdentifier
13 | cstr6suwn9.skadnetwork
14 |
15 |
16 | SKAdNetworkIdentifier
17 | 4fzdc2evr5.skadnetwork
18 |
19 |
20 | SKAdNetworkIdentifier
21 | 4pfyvq9l8r.skadnetwork
22 |
23 |
24 | SKAdNetworkIdentifier
25 | 2fnua5tdw4.skadnetwork
26 |
27 |
28 | SKAdNetworkIdentifier
29 | ydx93a7ass.skadnetwork
30 |
31 |
32 | SKAdNetworkIdentifier
33 | 5a6flpkh64.skadnetwork
34 |
35 |
36 | SKAdNetworkIdentifier
37 | p78axxw29g.skadnetwork
38 |
39 |
40 | SKAdNetworkIdentifier
41 | v72qych5uu.skadnetwork
42 |
43 |
44 | SKAdNetworkIdentifier
45 | ludvb6z3bs.skadnetwork
46 |
47 |
48 | SKAdNetworkIdentifier
49 | cp8zw746q7.skadnetwork
50 |
51 |
52 | SKAdNetworkIdentifier
53 | 3sh42y64q3.skadnetwork
54 |
55 |
56 | SKAdNetworkIdentifier
57 | c6k4g5qg8m.skadnetwork
58 |
59 |
60 | SKAdNetworkIdentifier
61 | s39g8k73mm.skadnetwork
62 |
63 |
64 | SKAdNetworkIdentifier
65 | 3qy4746246.skadnetwork
66 |
67 |
68 | SKAdNetworkIdentifier
69 | f38h382jlk.skadnetwork
70 |
71 |
72 | SKAdNetworkIdentifier
73 | hs6bdukanm.skadnetwork
74 |
75 |
76 | SKAdNetworkIdentifier
77 | v4nxqhlyqp.skadnetwork
78 |
79 |
80 | SKAdNetworkIdentifier
81 | wzmmz9fp6w.skadnetwork
82 |
83 |
84 | SKAdNetworkIdentifier
85 | yclnxrl5pm.skadnetwork
86 |
87 |
88 | SKAdNetworkIdentifier
89 | t38b2kh725.skadnetwork
90 |
91 |
92 | SKAdNetworkIdentifier
93 | 7ug5zh24hu.skadnetwork
94 |
95 |
96 | SKAdNetworkIdentifier
97 | gta9lk7p23.skadnetwork
98 |
99 |
100 | SKAdNetworkIdentifier
101 | vutu7akeur.skadnetwork
102 |
103 |
104 | SKAdNetworkIdentifier
105 | y5ghdn5j9k.skadnetwork
106 |
107 |
108 | SKAdNetworkIdentifier
109 | n6fk4nfna4.skadnetwork
110 |
111 |
112 | SKAdNetworkIdentifier
113 | v9wttpbfk9.skadnetwork
114 |
115 |
116 | SKAdNetworkIdentifier
117 | n38lu8286q.skadnetwork
118 |
119 |
120 | SKAdNetworkIdentifier
121 | 47vhws6wlr.skadnetwork
122 |
123 |
124 | SKAdNetworkIdentifier
125 | kbd757ywx3.skadnetwork
126 |
127 |
128 | SKAdNetworkIdentifier
129 | 9t245vhmpl.skadnetwork
130 |
131 |
132 | SKAdNetworkIdentifier
133 | eh6m2bh4zr.skadnetwork
134 |
135 |
136 | SKAdNetworkIdentifier
137 | a2p9lx4jpn.skadnetwork
138 |
139 |
140 | SKAdNetworkIdentifier
141 | 22mmun2rn5.skadnetwork
142 |
143 |
144 | SKAdNetworkIdentifier
145 | 4468km3ulz.skadnetwork
146 |
147 |
148 | SKAdNetworkIdentifier
149 | 2u9pt9hc89.skadnetwork
150 |
151 |
152 | SKAdNetworkIdentifier
153 | 8s468mfl3y.skadnetwork
154 |
155 |
156 | SKAdNetworkIdentifier
157 | klf5c3l5u5.skadnetwork
158 |
159 |
160 | SKAdNetworkIdentifier
161 | ppxm28t8ap.skadnetwork
162 |
163 |
164 | SKAdNetworkIdentifier
165 | ecpz2srf59.skadnetwork
166 |
167 |
168 | SKAdNetworkIdentifier
169 | uw77j35x4d.skadnetwork
170 |
171 |
172 | SKAdNetworkIdentifier
173 | pwa73g5rt2.skadnetwork
174 |
175 |
176 | SKAdNetworkIdentifier
177 | mlmmfzh3r3.skadnetwork
178 |
179 |
180 | SKAdNetworkIdentifier
181 | 578prtvx9j.skadnetwork
182 |
183 |
184 | SKAdNetworkIdentifier
185 | 4dzt52r2t5.skadnetwork
186 |
187 |
188 | SKAdNetworkIdentifier
189 | e5fvkxwrpn.skadnetwork
190 |
191 |
192 | SKAdNetworkIdentifier
193 | 8c4e2ghe7u.skadnetwork
194 |
195 |
196 | SKAdNetworkIdentifier
197 | zq492l623r.skadnetwork
198 |
199 |
200 | SKAdNetworkIdentifier
201 | 3rd42ekr43.skadnetwork
202 |
203 |
204 | SKAdNetworkIdentifier
205 | 3qcr597p9d.skadnetwork
206 |
207 |
208 | NSAppTransportSecurity
209 |
210 | NSAllowsArbitraryLoads
211 |
212 | NSAllowsArbitraryLoadsForMedia
213 |
214 | NSAllowsArbitraryLoadsInWebContent
215 |
216 |
217 |
218 |
219 |
--------------------------------------------------------------------------------
/Demo/AdmobSwitUIDemo/Info-demo2.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSUserTrackingUsageDescription
6 | DemoText
7 | GADApplicationIdentifier
8 | ca-app-pub-8128194504271891~2346699168
9 | SKAdNetworkItems
10 |
11 |
12 | SKAdNetworkIdentifier
13 | cstr6suwn9.skadnetwork
14 |
15 |
16 | SKAdNetworkIdentifier
17 | 4fzdc2evr5.skadnetwork
18 |
19 |
20 | SKAdNetworkIdentifier
21 | 4pfyvq9l8r.skadnetwork
22 |
23 |
24 | SKAdNetworkIdentifier
25 | 2fnua5tdw4.skadnetwork
26 |
27 |
28 | SKAdNetworkIdentifier
29 | ydx93a7ass.skadnetwork
30 |
31 |
32 | SKAdNetworkIdentifier
33 | 5a6flpkh64.skadnetwork
34 |
35 |
36 | SKAdNetworkIdentifier
37 | p78axxw29g.skadnetwork
38 |
39 |
40 | SKAdNetworkIdentifier
41 | v72qych5uu.skadnetwork
42 |
43 |
44 | SKAdNetworkIdentifier
45 | ludvb6z3bs.skadnetwork
46 |
47 |
48 | SKAdNetworkIdentifier
49 | cp8zw746q7.skadnetwork
50 |
51 |
52 | SKAdNetworkIdentifier
53 | c6k4g5qg8m.skadnetwork
54 |
55 |
56 | SKAdNetworkIdentifier
57 | s39g8k73mm.skadnetwork
58 |
59 |
60 | SKAdNetworkIdentifier
61 | 3qy4746246.skadnetwork
62 |
63 |
64 | SKAdNetworkIdentifier
65 | 3sh42y64q3.skadnetwork
66 |
67 |
68 | SKAdNetworkIdentifier
69 | f38h382jlk.skadnetwork
70 |
71 |
72 | SKAdNetworkIdentifier
73 | hs6bdukanm.skadnetwork
74 |
75 |
76 | SKAdNetworkIdentifier
77 | prcb7njmu6.skadnetwork
78 |
79 |
80 | SKAdNetworkIdentifier
81 | v4nxqhlyqp.skadnetwork
82 |
83 |
84 | SKAdNetworkIdentifier
85 | wzmmz9fp6w.skadnetwork
86 |
87 |
88 | SKAdNetworkIdentifier
89 | yclnxrl5pm.skadnetwork
90 |
91 |
92 | SKAdNetworkIdentifier
93 | t38b2kh725.skadnetwork
94 |
95 |
96 | SKAdNetworkIdentifier
97 | 7ug5zh24hu.skadnetwork
98 |
99 |
100 | SKAdNetworkIdentifier
101 | 9rd848q2bz.skadnetwork
102 |
103 |
104 | SKAdNetworkIdentifier
105 | y5ghdn5j9k.skadnetwork
106 |
107 |
108 | SKAdNetworkIdentifier
109 | n6fk4nfna4.skadnetwork
110 |
111 |
112 | SKAdNetworkIdentifier
113 | v9wttpbfk9.skadnetwork
114 |
115 |
116 | SKAdNetworkIdentifier
117 | n38lu8286q.skadnetwork
118 |
119 |
120 | SKAdNetworkIdentifier
121 | 47vhws6wlr.skadnetwork
122 |
123 |
124 | SKAdNetworkIdentifier
125 | kbd757ywx3.skadnetwork
126 |
127 |
128 | SKAdNetworkIdentifier
129 | 9t245vhmpl.skadnetwork
130 |
131 |
132 | SKAdNetworkIdentifier
133 | a2p9lx4jpn.skadnetwork
134 |
135 |
136 | SKAdNetworkIdentifier
137 | 22mmun2rn5.skadnetwork
138 |
139 |
140 | SKAdNetworkIdentifier
141 | 4468km3ulz.skadnetwork
142 |
143 |
144 | SKAdNetworkIdentifier
145 | 2u9pt9hc89.skadnetwork
146 |
147 |
148 | SKAdNetworkIdentifier
149 | 8s468mfl3y.skadnetwork
150 |
151 |
152 | SKAdNetworkIdentifier
153 | av6w8kgt66.skadnetwork
154 |
155 |
156 | SKAdNetworkIdentifier
157 | klf5c3l5u5.skadnetwork
158 |
159 |
160 | SKAdNetworkIdentifier
161 | ppxm28t8ap.skadnetwork
162 |
163 |
164 | SKAdNetworkIdentifier
165 | 424m5254lk.skadnetwork
166 |
167 |
168 | SKAdNetworkIdentifier
169 | ecpz2srf59.skadnetwork
170 |
171 |
172 | SKAdNetworkIdentifier
173 | uw77j35x4d.skadnetwork
174 |
175 |
176 | SKAdNetworkIdentifier
177 | mlmmfzh3r3.skadnetwork
178 |
179 |
180 | SKAdNetworkIdentifier
181 | 578prtvx9j.skadnetwork
182 |
183 |
184 | SKAdNetworkIdentifier
185 | 4dzt52r2t5.skadnetwork
186 |
187 |
188 | SKAdNetworkIdentifier
189 | gta9lk7p23.skadnetwork
190 |
191 |
192 | SKAdNetworkIdentifier
193 | e5fvkxwrpn.skadnetwork
194 |
195 |
196 | SKAdNetworkIdentifier
197 | 8c4e2ghe7u.skadnetwork
198 |
199 |
200 | SKAdNetworkIdentifier
201 | zq492l623r.skadnetwork
202 |
203 |
204 | SKAdNetworkIdentifier
205 | 3rd42ekr43.skadnetwork
206 |
207 |
208 | SKAdNetworkIdentifier
209 | 3qcr597p9d.skadnetwork
210 |
211 |
212 | NSAppTransportSecurity
213 |
214 | NSAllowsArbitraryLoads
215 |
216 | NSAllowsArbitraryLoadsForMedia
217 |
218 | NSAllowsArbitraryLoadsInWebContent
219 |
220 |
221 |
222 |
223 |
--------------------------------------------------------------------------------
/Demo/AdmobSwitUIDemo/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "pins" : [
3 | {
4 | "identity" : "googleappmeasurement",
5 | "kind" : "remoteSourceControl",
6 | "location" : "https://github.com/google/GoogleAppMeasurement.git",
7 | "state" : {
8 | "revision" : "bf3bb24f6b60a7acedaef504e9ce97154203217a",
9 | "version" : "10.22.0"
10 | }
11 | },
12 | {
13 | "identity" : "googleutilities",
14 | "kind" : "remoteSourceControl",
15 | "location" : "https://github.com/google/GoogleUtilities.git",
16 | "state" : {
17 | "revision" : "830ffa9276e10267881f2697283c2fcd867603fd",
18 | "version" : "7.13.0"
19 | }
20 | },
21 | {
22 | "identity" : "lbtatools",
23 | "kind" : "remoteSourceControl",
24 | "location" : "https://github.com/bhlvoong/LBTATools",
25 | "state" : {
26 | "revision" : "dce147bfbdc0417a4b430ec220c088629e9dc81d",
27 | "version" : "1.0.17"
28 | }
29 | },
30 | {
31 | "identity" : "nanopb",
32 | "kind" : "remoteSourceControl",
33 | "location" : "https://github.com/firebase/nanopb.git",
34 | "state" : {
35 | "revision" : "b7e1104502eca3a213b46303391ca4d3bc8ddec1",
36 | "version" : "2.30910.0"
37 | }
38 | },
39 | {
40 | "identity" : "promises",
41 | "kind" : "remoteSourceControl",
42 | "location" : "https://github.com/google/promises.git",
43 | "state" : {
44 | "revision" : "540318ecedd63d883069ae7f1ed811a2df00b6ac",
45 | "version" : "2.4.0"
46 | }
47 | },
48 | {
49 | "identity" : "swift-package-manager-google-mobile-ads",
50 | "kind" : "remoteSourceControl",
51 | "location" : "https://github.com/googleads/swift-package-manager-google-mobile-ads.git",
52 | "state" : {
53 | "revision" : "70516c9e799a366ff90c1a70c09c48f7c076fd8a",
54 | "version" : "10.14.0"
55 | }
56 | },
57 | {
58 | "identity" : "swift-package-manager-google-user-messaging-platform",
59 | "kind" : "remoteSourceControl",
60 | "location" : "https://github.com/googleads/swift-package-manager-google-user-messaging-platform.git",
61 | "state" : {
62 | "revision" : "668673ea23b3e71b9f2540d8fb9464c4dc32ecc0",
63 | "version" : "2.2.0"
64 | }
65 | }
66 | ],
67 | "version" : 2
68 | }
69 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 5.9
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "AdmobSwiftUI",
8 | defaultLocalization: "en",
9 | platforms: [.iOS(.v14)],
10 | products: [
11 | // Products define the executables and libraries a package produces, and make them visible to other packages.
12 | .library(
13 | name: "AdmobSwiftUI",
14 | targets: ["AdmobSwiftUI"]),
15 | ],
16 | dependencies: [
17 | // Dependencies declare other packages that this package depends on.
18 | // .package(url: /* package url */, from: "1.0.0"),
19 | .package(url: "https://github.com/googleads/swift-package-manager-google-mobile-ads.git", from: "11.2.0"),
20 | .package(url: "https://github.com/bhlvoong/LBTATools", from: "1.0.17"),
21 | ],
22 | targets: [
23 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
24 | // Targets can depend on other targets in this package, and on products in packages this package depends on.
25 | .target(
26 | name: "AdmobSwiftUI",
27 | dependencies: [
28 | .product(name: "GoogleMobileAds", package: "swift-package-manager-google-mobile-ads"),
29 | "LBTATools"
30 | ]),
31 | .testTarget(
32 | name: "AdmobSwiftUITests",
33 | dependencies: ["AdmobSwiftUI"]),
34 | ]
35 | )
36 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AdmobSwiftUI
2 |
3 | AdmobSwiftUI is a Swift package that integrates Admob ads into SwiftUI. This package implements several ways to use Admob in SwiftUI:
4 |
5 | - Banner
6 | - Interstitial
7 | - App Open
8 | - Reward
9 | - Reward Interstitial
10 | - Native
11 |
12 | ## Requirements
13 |
14 | - iOS 14.0+
15 | - Google Mobile Ads SDK 10.6.0+
16 |
17 | ## Installation
18 |
19 | You can install AdmobSwiftUI using Swift Package Manager by adding the following URL to your project:
20 |
21 | ```
22 | https://github.com/dearhui/AdmobSwiftUI.git
23 | ```
24 | Before building the project, make sure you've added the -ObjC flag to the "Other Linker Flags" in the "Build Settings".
25 |
26 | ## Configuration
27 | To use AdmobSwiftUI, you need to add some key values to your Info.plist as required by the Google Mobile Ads SDK. Please refer to the SDK documentation for more details.
28 |
29 | Additionally, you need to start the Google Mobile Ads SDK at the start of your app. Add the following code to your @main struct:
30 |
31 | ```swift
32 | @main
33 | struct AdmobSwitUIDemoApp: App {
34 |
35 | init() {
36 | GADMobileAds.sharedInstance().start(completionHandler: nil)
37 | }
38 |
39 | var body: some Scene {
40 | WindowGroup {
41 | ContentView()
42 | }
43 | }
44 | }
45 | ```
46 |
47 | ## Usage
48 |
49 | First, you need to import AdmobSwiftUI in your SwiftUI file and initialize all the ad components you need.
50 |
51 | ```swift
52 | import SwiftUI
53 | import AdmobSwiftUI
54 |
55 | struct ContentView: View {
56 | @StateObject private var nativeViewModel = NativeAdViewModel()
57 | private let adViewControllerRepresentable = AdViewControllerRepresentable()
58 | private let adCoordinator = InterstitialAdCoordinator()
59 | private let rewardCoordinator = RewardedAdCoordinator()
60 | ```
61 |
62 | Then, you can include Banner ads in your view, or show Interstitial or Reward ads when the user performs a certain action.
63 |
64 | ```swift
65 | var body: some View {
66 | ScrollView {
67 | VStack (spacing: 20) {
68 |
69 | Button("Show App Open") {
70 | Task {
71 | do {
72 | let ad = try await adCoordinator.loadAppOpenAd()
73 | ad.present(fromRootViewController: adViewControllerRepresentable.viewController)
74 | } catch {
75 | print(error.localizedDescription)
76 | }
77 | }
78 | }
79 |
80 | Button("Show reward InterstitialAd") {
81 | Task {
82 | do {
83 | let reward = try await rewardCoordinator.loadInterstitialAd()
84 | reward.present(fromRootViewController: adViewControllerRepresentable.viewController) {
85 | print("Reward amount: \(reward.adReward.amount)")
86 | }
87 | } catch {
88 | print(error.localizedDescription)
89 | }
90 | }
91 | }
92 |
93 | BannerView()
94 | .frame(height: 50)
95 |
96 | NativeAdView(nativeViewModel: nativeViewModel)
97 | .frame(height: 300) // 250 ~ 300
98 | .onAppear {
99 | nativeViewModel.refreshAd()
100 | }
101 | }
102 | }
103 | .padding()
104 | .background {
105 | // Add the adViewControllerRepresentable to the background so it
106 | // doesn't influence the placement of other views in the view hierarchy.
107 | adViewControllerRepresentable
108 | .frame(width: .zero, height: .zero)
109 | }
110 | }
111 | }
112 | ```
113 |
114 | ## Note
115 |
116 | This package uses Google AdMob, make sure your project has imported and configured the Google Mobile Ads SDK properly.
117 |
118 | ## Contribution
119 |
120 | Any form of contribution is welcome, including feature requests, bug reports, or pull requests.
121 |
122 | ## License
123 |
124 | AdmobSwiftUI is released under the MIT license. See [LICENSE](LICENSE) for details.
125 |
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/AdmobSwiftUI.swift:
--------------------------------------------------------------------------------
1 | public struct AdmobSwiftUI {
2 | public private(set) var text = "Hello, World!"
3 |
4 | public init() {
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Banner/BannerView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BannerView.swift
3 | //
4 | //
5 | // Created by minghui on 2023/6/13.
6 | //
7 |
8 | import SwiftUI
9 | import GoogleMobileAds
10 |
11 | public struct BannerView: UIViewControllerRepresentable {
12 | @State private var viewWidth: CGFloat = .zero
13 | private let bannerView = GADBannerView()
14 | private let adUnitID: String
15 |
16 | public init(adUnitID: String = "ca-app-pub-3940256099942544/2934735716") {
17 | self.adUnitID = adUnitID
18 | }
19 |
20 | public func makeUIViewController(context: Context) -> some UIViewController {
21 | let bannerViewController = BannerViewController()
22 | bannerView.adUnitID = adUnitID
23 | bannerView.rootViewController = bannerViewController
24 | bannerView.delegate = context.coordinator
25 | bannerViewController.view.addSubview(bannerView)
26 | bannerViewController.delegate = context.coordinator
27 |
28 | return bannerViewController
29 | }
30 |
31 | public func makeCoordinator() -> Coordinator {
32 | Coordinator(self)
33 | }
34 |
35 | public func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
36 | print("size: \(viewWidth)")
37 | guard viewWidth != .zero else { return }
38 |
39 | // Request a banner ad with the updated viewWidth.
40 | bannerView.adSize = GADCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(viewWidth)
41 | bannerView.load(GADRequest())
42 | }
43 |
44 | public class Coordinator: NSObject, BannerViewControllerWidthDelegate, GADBannerViewDelegate {
45 | let parent: BannerView
46 |
47 | init(_ parent: BannerView) {
48 | self.parent = parent
49 | }
50 |
51 | // MARK: - BannerViewControllerWidthDelegate methods
52 |
53 | func bannerViewController(_ bannerViewController: BannerViewController, didUpdate width: CGFloat) {
54 | // Pass the viewWidth from Coordinator to BannerView.
55 | parent.viewWidth = width
56 | }
57 |
58 | public func bannerViewDidReceiveAd(_ bannerView: GADBannerView) {
59 | print("\(#function) called")
60 | }
61 |
62 | public func bannerView(_ bannerView: GADBannerView, didFailToReceiveAdWithError error: Error) {
63 | print("\(#function) called")
64 | }
65 |
66 | public func bannerViewDidRecordImpression(_ bannerView: GADBannerView) {
67 | print("\(#function) called")
68 | }
69 |
70 | public func bannerViewWillPresentScreen(_ bannerView: GADBannerView) {
71 | print("\(#function) called")
72 | }
73 |
74 | public func bannerViewWillDismissScreen(_ bannerView: GADBannerView) {
75 | print("\(#function) called")
76 | }
77 |
78 | public func bannerViewDidDismissScreen(_ bannerView: GADBannerView) {
79 | print("\(#function) called")
80 | }
81 | }
82 | }
83 |
84 | struct BannerView_Previews: PreviewProvider {
85 | static var previews: some View {
86 | BannerView()
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Banner/BannerViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BannerViewController.swift
3 | //
4 | //
5 | // Created by minghui on 2023/6/13.
6 | //
7 |
8 | import UIKit
9 |
10 | // Delegate methods for receiving width update messages.
11 |
12 | protocol BannerViewControllerWidthDelegate: AnyObject {
13 | func bannerViewController(_ bannerViewController: BannerViewController, didUpdate width: CGFloat)
14 | }
15 |
16 | class BannerViewController: UIViewController {
17 | weak var delegate: BannerViewControllerWidthDelegate?
18 |
19 | override func viewDidAppear(_ animated: Bool) {
20 | super.viewDidAppear(animated)
21 |
22 | // Tell the delegate the initial ad width.
23 | delegate?.bannerViewController(
24 | self, didUpdate: view.frame.inset(by: view.safeAreaInsets).size.width)
25 | }
26 |
27 | override func viewWillTransition(
28 | to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator
29 | ) {
30 | coordinator.animate { _ in
31 | // do nothing
32 | } completion: { _ in
33 | // Notify the delegate of ad width changes.
34 | self.delegate?.bannerViewController(
35 | self, didUpdate: self.view.frame.inset(by: self.view.safeAreaInsets).size.width)
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Extensions/UIColor+Extensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // File.swift
3 | //
4 | //
5 | // Created by minghui on 2023/6/15.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIColor {
11 | convenience init(hex: String, alpha: CGFloat = 1.0) {
12 | var hexFormatted: String = hex.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
13 | hexFormatted = hexFormatted.replacingOccurrences(of: "#", with: "")
14 |
15 | assert(hexFormatted.count == 6, "Invalid hex code used.")
16 |
17 | var rgbValue: UInt64 = 0
18 | Scanner(string: hexFormatted).scanHexInt64(&rgbValue)
19 |
20 | self.init(
21 | red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
22 | green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
23 | blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
24 | alpha: alpha
25 | )
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Fullscreen/AdViewControllerRepresentable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // File.swift
3 | //
4 | //
5 | // Created by minghui on 2023/6/13.
6 | //
7 |
8 | import SwiftUI
9 | import GoogleMobileAds
10 |
11 | // MARK: - Helper to present Interstitial Ad
12 | public struct AdViewControllerRepresentable: UIViewControllerRepresentable {
13 | public var viewController = UIViewController()
14 |
15 | public init() {
16 |
17 | }
18 |
19 | public func makeUIViewController(context: Context) -> some UIViewController {
20 | return viewController
21 | }
22 |
23 | public func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {}
24 | }
25 |
26 | /*
27 | private let adViewControllerRepresentable = AdViewControllerRepresentable()
28 |
29 | .background {
30 | // Add the adViewControllerRepresentable to the background so it
31 | // doesn't influence the placement of other views in the view hierarchy.
32 | adViewControllerRepresentable
33 | .frame(width: .zero, height: .zero)
34 | }
35 | */
36 |
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Fullscreen/InterstitialAdCoordinator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // InterstitialAdCoordinator.swift
3 | //
4 | //
5 | // Created by minghui on 2023/6/13.
6 | //
7 |
8 | import GoogleMobileAds
9 | import SwiftUI
10 |
11 | public class InterstitialAdCoordinator: NSObject, GADFullScreenContentDelegate {
12 | private var appOpenAd: GADAppOpenAd?
13 | private var interstitial: GADInterstitialAd?
14 | private let appOpenadUnitID: String
15 | private let adUnitID: String
16 |
17 | public init(appOpenadUnitID: String = "ca-app-pub-3940256099942544/5662855259", adUnitID: String = "ca-app-pub-3940256099942544/4411468910") {
18 | self.adUnitID = adUnitID
19 | self.appOpenadUnitID = appOpenadUnitID
20 | }
21 |
22 | public func loadAd() {
23 | clean()
24 | GADInterstitialAd.load(withAdUnitID: adUnitID, request: GADRequest()) { ad, error in
25 | self.interstitial = ad
26 | self.interstitial?.fullScreenContentDelegate = self
27 | }
28 | }
29 |
30 | public func showAd(from viewController: UIViewController) {
31 | guard let interstitial = interstitial else {
32 | return print("Ad wasn't ready")
33 | }
34 |
35 | interstitial.present(fromRootViewController: viewController)
36 | }
37 |
38 | // MARK: - Async/await
39 | public func loadInterstitialAd() async throws -> GADInterstitialAd {
40 | clean()
41 |
42 | return try await withCheckedThrowingContinuation { continuation in
43 | GADInterstitialAd.load(withAdUnitID: adUnitID, request: GADRequest()) { ad, error in
44 | if let error = error {
45 | continuation.resume(throwing: error)
46 | } else if let ad = ad {
47 | ad.fullScreenContentDelegate = self
48 | continuation.resume(returning: ad)
49 | }
50 | }
51 | }
52 | }
53 |
54 | public func loadAppOpenAd() async throws -> GADAppOpenAd {
55 | clean()
56 |
57 | return try await withCheckedThrowingContinuation { continuation in
58 | GADAppOpenAd.load(withAdUnitID: appOpenadUnitID, request: GADRequest()) { ad, error in
59 | if let error = error {
60 | continuation.resume(throwing: error)
61 | } else if let ad = ad {
62 | ad.fullScreenContentDelegate = self
63 | continuation.resume(returning: ad)
64 | }
65 | }
66 | }
67 | }
68 |
69 | private func clean() {
70 | interstitial = nil
71 | appOpenAd = nil
72 | }
73 |
74 | // MARK: - GADFullScreenContentDelegate methods
75 | public func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
76 | clean()
77 | }
78 | }
79 |
80 | // Use
81 | /*
82 | struct SampleView: View {
83 | private let adViewControllerRepresentable = AdViewControllerRepresentable()
84 | private let adCoordinator = InterstitialAdCoordinator()
85 |
86 | var body: some View {
87 | Text("Hello, World!")
88 | .background {
89 | // Add the adViewControllerRepresentable to the background so it
90 | // does not influence the placement of other views in the view hierarchy.
91 | adViewControllerRepresentable
92 | .frame(width: .zero, height: .zero)
93 | }
94 |
95 | Button("Load an ad") {
96 | adCoordinator.loadAd()
97 | }
98 |
99 | Button("Watch an ad") {
100 | adCoordinator.showAd(from: adViewControllerRepresentable.viewController)
101 | }
102 | }
103 | }
104 | */
105 |
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Fullscreen/RewardedAdCoordinator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RewardedAdCoordinator.swift
3 | //
4 | //
5 | // Created by minghui on 2023/6/13.
6 | //
7 |
8 | import SwiftUI
9 | import GoogleMobileAds
10 |
11 | public class RewardedAdCoordinator: NSObject, GADFullScreenContentDelegate {
12 | private var rewardedInterstitialAd: GADRewardedInterstitialAd?
13 | private var rewardedAd: GADRewardedAd?
14 | private let adUnitID: String
15 | private let InterstitialID: String
16 |
17 | public init(adUnitID: String = "ca-app-pub-3940256099942544/1712485313", InterstitialID: String = "ca-app-pub-3940256099942544/6978759866") {
18 | self.adUnitID = adUnitID
19 | self.InterstitialID = InterstitialID
20 | }
21 |
22 | public func loadAd() {
23 | clean()
24 | GADRewardedAd.load(withAdUnitID: adUnitID, request: GADRequest()) { ad, error in
25 | self.rewardedAd = ad
26 | self.rewardedAd?.fullScreenContentDelegate = self
27 | }
28 | }
29 |
30 | // MARK: - async/await
31 |
32 | public func loadInterstitialAd() async throws -> GADRewardedInterstitialAd {
33 | clean()
34 | return try await withCheckedThrowingContinuation { continuation in
35 | GADRewardedInterstitialAd.load(withAdUnitID: InterstitialID, request: GADRequest()) { ad, error in
36 | if let error = error {
37 | continuation.resume(throwing: error)
38 | } else if let ad = ad {
39 | ad.fullScreenContentDelegate = self
40 | continuation.resume(returning: ad)
41 | }
42 | }
43 | }
44 | }
45 |
46 | public func loadRewardedAd() async throws -> GADRewardedAd {
47 | clean()
48 | return try await withCheckedThrowingContinuation { continuation in
49 | GADRewardedAd.load(withAdUnitID: adUnitID, request: GADRequest()) { ad, error in
50 | if let error = error {
51 | continuation.resume(throwing: error)
52 | } else if let ad = ad {
53 | ad.fullScreenContentDelegate = self
54 | continuation.resume(returning: ad)
55 | }
56 | }
57 | }
58 | }
59 |
60 | private func clean() {
61 | self.rewardedInterstitialAd = nil
62 | self.rewardedAd = nil
63 | }
64 |
65 | public func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
66 | clean()
67 | }
68 |
69 | public func showAd(from viewController: UIViewController, userDidEarnRewardHandler completion: @escaping (Int) -> Void) {
70 | guard let rewardedAd = rewardedAd else {
71 | return print("Ad wasn't ready")
72 | }
73 |
74 | rewardedAd.present(fromRootViewController: viewController) {
75 | let reward = rewardedAd.adReward
76 | print("Reward amount: \(reward.amount)")
77 | completion(reward.amount.intValue)
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Native/NativeAdBannerView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NativeAdBannerView.swift
3 | //
4 | //
5 | // Created by minghui on 2023/6/15.
6 | //
7 |
8 | import GoogleMobileAds
9 | import UIKit
10 | import LBTATools
11 |
12 | class NativeAdBannerView: GADNativeAdView {
13 |
14 | let adTag: UILabel = UILabel(text: "AD", font: .systemFont(ofSize: 11, weight: .semibold), textColor: .white, textAlignment: .center)
15 | let headlineLabel = UILabel(text: "", font: .systemFont(ofSize: 15, weight: .medium), textColor: .label)
16 | let iconImageView = UIImageView()
17 | let bodyLabel = UILabel(text: "", font: .systemFont(ofSize: 14, weight: .regular), textColor: .secondaryLabel)
18 | let starRatingImageView = UIImageView()
19 |
20 | override init(frame: CGRect) {
21 | super.init(frame: frame)
22 | setupViews()
23 | }
24 |
25 | func setupViews() {
26 | self.headlineView = headlineLabel
27 | self.iconView = iconImageView
28 | self.bodyView = bodyLabel
29 |
30 | adTag.withWidth(20)
31 | adTag.backgroundColor = .orange
32 | adTag.layer.cornerRadius = 2
33 | adTag.clipsToBounds = true
34 |
35 | // config 1:1
36 | iconImageView.heightAnchor.constraint(equalTo: iconImageView.widthAnchor, multiplier: 1).isActive = true
37 | iconImageView.layer.cornerRadius = 4
38 | iconImageView.clipsToBounds = true
39 |
40 | headlineLabel.numberOfLines = 1
41 | headlineLabel.lineBreakMode = .byWordWrapping
42 |
43 | bodyLabel.numberOfLines = 2
44 | bodyLabel.lineBreakMode = .byWordWrapping
45 |
46 | let headerStack = hstack(headlineLabel, adTag)
47 | let leftStack = stack(headerStack, bodyLabel)
48 |
49 | hstack(leftStack, iconImageView, spacing: 8).withMargins(.allSides(8))
50 | }
51 |
52 | required init?(coder aDecoder: NSCoder) {
53 | fatalError("init(coder:) has not been implemented")
54 | }
55 | }
56 |
57 |
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Native/NativeAdCardView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // File.swift
3 | //
4 | //
5 | // Created by minghui on 2023/6/15.
6 | //
7 |
8 | import GoogleMobileAds
9 | import UIKit
10 | import LBTATools
11 |
12 | class NativeAdCardView: GADNativeAdView {
13 |
14 | let adTag: UILabel = UILabel(text: "AD", font: .systemFont(ofSize: 10, weight: .semibold), textColor: .white)
15 | let headlineLabel = UILabel(text: "", font: .systemFont(ofSize: 17, weight: .medium), textColor: .label)
16 | let myMediaView = GADMediaView()
17 | let callToActionButton = UIButton(title: "", titleColor: .white, font: .boldSystemFont(ofSize: 18), backgroundColor: UIColor(hex: "#3871E0"), target: nil, action: nil)
18 | let iconImageView = UIImageView()
19 | let bodyLabel = UILabel(text: "", font: .systemFont(ofSize: 14, weight: .regular), textColor: .label)
20 | let starRatingImageView = UIImageView()
21 | let advertiserLabel = UILabel(text: "", font: .systemFont(ofSize: 14, weight: .regular), textColor: .label)
22 |
23 | override init(frame: CGRect) {
24 | super.init(frame: frame)
25 | setupViews()
26 | }
27 |
28 | func setupViews() {
29 | self.headlineView = headlineLabel
30 |
31 | self.advertiserView = advertiserLabel
32 |
33 | myMediaView.translatesAutoresizingMaskIntoConstraints = false
34 | myMediaView.heightAnchor.constraint(equalTo: myMediaView.widthAnchor, multiplier: 9.0/16.0).isActive = true
35 | self.mediaView = myMediaView
36 |
37 | callToActionButton.isUserInteractionEnabled = false
38 | callToActionButton.layer.cornerRadius = 8
39 | callToActionButton.clipsToBounds = true
40 | self.callToActionView = callToActionButton
41 |
42 | iconImageView.layer.cornerRadius = 4
43 | iconImageView.clipsToBounds = true
44 | iconImageView.withWidth(40).withHeight(40)
45 | self.iconView = iconImageView
46 |
47 | bodyLabel.numberOfLines = 2
48 | bodyLabel.isUserInteractionEnabled = false
49 | bodyLabel.textColor = .secondaryLabel
50 | self.bodyView = bodyLabel
51 |
52 | starRatingImageView.withWidth(100).withHeight(17)
53 | self.starRatingView = starRatingImageView
54 |
55 | adTag.withWidth(25)
56 | adTag.textAlignment = .center
57 | adTag.backgroundColor = .orange
58 | adTag.layer.cornerRadius = 2
59 | adTag.clipsToBounds = true
60 | adTag.text = NSLocalizedString("AD", bundle: .module, comment: "Ad tag label")
61 |
62 | // avoid star width to long add space view
63 | let starRattingStack = hstack(adTag, starRatingImageView, advertiserLabel, UIView(), spacing: 4)
64 | let headlineStarStack = stack(headlineLabel, starRattingStack, spacing: 8)
65 | // avoid ad validator when icon hidden add stack and space view
66 | let iconHeadlineStack = hstack(stack(iconImageView), headlineStarStack, UIView(), spacing: 8)
67 | let buttonStack = hstack(callToActionButton.withHeight(39)).withMargins(.init(top: 0, left: 10, bottom: 0, right: 10))
68 | let bottomStack = stack(iconHeadlineStack, bodyLabel, buttonStack, spacing: 8).withMargins(.allSides(10))
69 | stack(myMediaView, bottomStack)
70 | }
71 |
72 | required init?(coder aDecoder: NSCoder) {
73 | fatalError("init(coder:) has not been implemented")
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Native/NativeAdView.swift:
--------------------------------------------------------------------------------
1 | import GoogleMobileAds
2 | import SwiftUI
3 |
4 | public struct NativeAdView: UIViewRepresentable {
5 | public typealias UIViewType = GADNativeAdView
6 |
7 | @ObservedObject var nativeViewModel: NativeAdViewModel
8 | var style: NativeAdViewStyle
9 |
10 | public init(nativeViewModel: NativeAdViewModel, style: NativeAdViewStyle = .basic) {
11 | self.nativeViewModel = nativeViewModel
12 | self.style = style
13 | }
14 |
15 | public func makeUIView(context: Context) -> GADNativeAdView {
16 | return style.view
17 | }
18 |
19 | func removeCurrentSizeConstraints(from mediaView: UIView) {
20 | mediaView.constraints.forEach { constraint in
21 | if constraint.firstAttribute == .width || constraint.firstAttribute == .height {
22 | mediaView.removeConstraint(constraint)
23 | }
24 | }
25 | }
26 |
27 | public func updateUIView(_ nativeAdView: GADNativeAdView, context: Context) {
28 | guard let nativeAd = nativeViewModel.nativeAd else { return }
29 |
30 | if let mediaView = nativeAdView.mediaView {
31 | mediaView.contentMode = .scaleAspectFill
32 | mediaView.clipsToBounds = true
33 |
34 | let aspectRatio = nativeAd.mediaContent.aspectRatio
35 |
36 | debugPrint("Google aspectRatio: \(aspectRatio), hasVideoContent: \(nativeAd.mediaContent.hasVideoContent)")
37 |
38 | if style == .largeBanner {
39 | removeCurrentSizeConstraints(from: mediaView)
40 | if aspectRatio > 0 {
41 | if aspectRatio > 1 {
42 | mediaView.widthAnchor.constraint(equalTo: mediaView.heightAnchor, multiplier: aspectRatio).isActive = true
43 | } else {
44 | mediaView.widthAnchor.constraint(equalTo: mediaView.heightAnchor, multiplier: 1).isActive = true
45 | }
46 | } else {
47 | mediaView.widthAnchor.constraint(equalTo: mediaView.heightAnchor, multiplier: 16/9).isActive = true
48 | }
49 | }
50 | }
51 |
52 | // headline require
53 | (nativeAdView.headlineView as? UILabel)?.text = nativeAd.headline
54 |
55 | // body
56 | (nativeAdView.bodyView as? UILabel)?.text = nativeAd.body
57 | nativeAdView.bodyView?.isHidden = nativeAd.body == nil
58 |
59 | // icon
60 | (nativeAdView.iconView as? UIImageView)?.image = nativeAd.icon?.image
61 | nativeAdView.iconView?.isHidden = (nativeAd.icon == nil)
62 |
63 | // ratting
64 | let starRattingImage = imageOfStars(from: nativeAd.starRating)
65 | (nativeAdView.starRatingView as? UIImageView)?.image = starRattingImage
66 | nativeAdView.starRatingView?.isHidden = (starRattingImage == nil)
67 |
68 | // store
69 | (nativeAdView.storeView as? UILabel)?.text = nativeAd.store
70 | nativeAdView.storeView?.isHidden = nativeAd.store == nil
71 |
72 | // price
73 | (nativeAdView.priceView as? UILabel)?.text = nativeAd.price
74 | nativeAdView.priceView?.isHidden = nativeAd.price == nil
75 |
76 | // advertiser
77 | (nativeAdView.advertiserView as? UILabel)?.text = nativeAd.advertiser
78 | nativeAdView.advertiserView?.isHidden = (nativeAd.advertiser == nil)
79 |
80 | // button
81 | (nativeAdView.callToActionView as? UIButton)?.setTitle(nativeAd.callToAction, for: .normal)
82 | nativeAdView.callToActionView?.isHidden = nativeAd.callToAction == nil
83 | nativeAdView.callToActionView?.isUserInteractionEnabled = false
84 |
85 | if style == .largeBanner, let body = nativeAd.body, body.count > 0 {
86 | nativeAdView.callToActionView?.isHidden = true
87 | }
88 |
89 | // Associate the native ad view with the native ad object. This is required to make the ad clickable.
90 | // Note: this should always be done after populating the ad views.
91 | nativeAdView.nativeAd = nativeAd
92 | }
93 | }
94 |
95 | extension NativeAdView {
96 |
97 | func imageOfStars(from starRating: NSDecimalNumber?) -> UIImage? {
98 | guard let rating = starRating?.doubleValue else {
99 | return nil
100 | }
101 |
102 | let bundle = Bundle.module
103 |
104 | if rating >= 5 {
105 | return UIImage(named: "stars_5", in: bundle, compatibleWith: nil)
106 | } else if rating >= 4.5 {
107 | return UIImage(named: "stars_4_5", in: bundle, compatibleWith: nil)
108 | } else if rating >= 4 {
109 | return UIImage(named: "stars_4", in: bundle, compatibleWith: nil)
110 | } else if rating >= 3.5 {
111 | return UIImage(named: "stars_3_5", in: bundle, compatibleWith: nil)
112 | } else {
113 | return nil
114 | }
115 | }
116 | }
117 |
118 |
119 | struct NativeAdView_Previews: PreviewProvider {
120 | static var previews: some View {
121 | // 创建一个模拟的 NativeAdViewModel
122 | let viewModel = NativeAdViewModel() // 可能需要根据你的实际情况进行修改
123 | // 假设 NativeAdViewStyle.basic 是一个有效的样式
124 | ScrollView {
125 | VStack {
126 | NativeAdView(nativeViewModel: viewModel, style: .card)
127 | .frame(width: .infinity, height: 300)
128 | .background(Color.red)
129 | }
130 | .padding()
131 | }
132 | .background(Color.gray)
133 | }
134 | }
135 |
136 |
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Native/NativeAdViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftUIView.swift
3 | //
4 | //
5 | // Created by minghui on 2023/6/14.
6 | //
7 |
8 | import SwiftUI
9 | import GoogleMobileAds
10 |
11 | public class NativeAdViewModel: NSObject, ObservableObject, GADNativeAdLoaderDelegate {
12 | @Published public var nativeAd: GADNativeAd?
13 | @Published public var isLoading: Bool = false
14 | private var adLoader: GADAdLoader!
15 | private var adUnitID: String
16 | private var lastRequestTime: Date?
17 | public var requestInterval: Int
18 | private static var cachedAds: [String: GADNativeAd] = [:]
19 | private static var lastRequestTimes: [String: Date] = [:]
20 |
21 | public init(adUnitID: String = "ca-app-pub-3940256099942544/3986624511", requestInterval: Int = 1 * 60) {
22 | self.adUnitID = adUnitID
23 | self.requestInterval = requestInterval
24 | self.nativeAd = NativeAdViewModel.cachedAds[adUnitID]
25 | self.lastRequestTime = NativeAdViewModel.lastRequestTimes[adUnitID]
26 | }
27 |
28 | public func refreshAd() {
29 | let now = Date()
30 |
31 | if nativeAd != nil, let lastRequest = lastRequestTime, now.timeIntervalSince(lastRequest) < Double(requestInterval) {
32 | print("The last request was made less than \(requestInterval / 60) minutes ago. New request is canceled.")
33 | return
34 | }
35 |
36 | guard !isLoading else {
37 | print("Previous request is still loading, new request is canceled.")
38 | return
39 | }
40 |
41 | isLoading = true
42 | lastRequestTime = now
43 | NativeAdViewModel.lastRequestTimes[adUnitID] = now
44 |
45 | let adViewOptions = GADNativeAdViewAdOptions()
46 | adViewOptions.preferredAdChoicesPosition = .topRightCorner
47 | adLoader = GADAdLoader(adUnitID: adUnitID, rootViewController: nil, adTypes: [.native], options: [adViewOptions])
48 | adLoader.delegate = self
49 | adLoader.load(GADRequest())
50 | }
51 |
52 | public func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADNativeAd) {
53 | self.nativeAd = nativeAd
54 | nativeAd.delegate = self
55 | self.isLoading = false
56 | NativeAdViewModel.cachedAds[adUnitID] = nativeAd
57 | nativeAd.mediaContent.videoController.delegate = self
58 | }
59 |
60 | public func adLoader(_ adLoader: GADAdLoader, didFailToReceiveAdWithError error: Error) {
61 | print("\(adLoader) failed with error: \(error.localizedDescription)")
62 | self.isLoading = false
63 | }
64 | }
65 |
66 | extension NativeAdViewModel: GADVideoControllerDelegate {
67 | // GADVideoControllerDelegate methods
68 | public func videoControllerDidPlayVideo(_ videoController: GADVideoController) {
69 | // Implement this method to receive a notification when the video controller
70 | // begins playing the ad.
71 | }
72 |
73 | public func videoControllerDidPauseVideo(_ videoController: GADVideoController) {
74 | // Implement this method to receive a notification when the video controller
75 | // pauses the ad.
76 | }
77 |
78 | public func videoControllerDidEndVideoPlayback(_ videoController: GADVideoController) {
79 | // Implement this method to receive a notification when the video controller
80 | // stops playing the ad.
81 | }
82 |
83 | public func videoControllerDidMuteVideo(_ videoController: GADVideoController) {
84 | // Implement this method to receive a notification when the video controller
85 | // mutes the ad.
86 | }
87 |
88 | public func videoControllerDidUnmuteVideo(_ videoController: GADVideoController) {
89 | // Implement this method to receive a notification when the video controller
90 | // unmutes the ad.
91 | }
92 | }
93 |
94 | // MARK: - GADNativeAdDelegate implementation
95 | extension NativeAdViewModel: GADNativeAdDelegate {
96 | public func nativeAdDidRecordClick(_ nativeAd: GADNativeAd) {
97 | print("\(#function) called")
98 | }
99 |
100 | public func nativeAdDidRecordImpression(_ nativeAd: GADNativeAd) {
101 | print("\(#function) called")
102 | }
103 |
104 | public func nativeAdWillPresentScreen(_ nativeAd: GADNativeAd) {
105 | print("\(#function) called")
106 | }
107 |
108 | public func nativeAdWillDismissScreen(_ nativeAd: GADNativeAd) {
109 | print("\(#function) called")
110 | }
111 |
112 | public func nativeAdDidDismissScreen(_ nativeAd: GADNativeAd) {
113 | print("\(#function) called")
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Native/NativeAdViewStyle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // File.swift
3 | //
4 | //
5 | // Created by minghui on 2023/6/15.
6 | //
7 |
8 | import GoogleMobileAds
9 | import SwiftUI
10 |
11 | public enum NativeAdViewStyle {
12 | case basic
13 | case card
14 | case banner
15 | case largeBanner
16 |
17 | var view: GADNativeAdView {
18 | switch self {
19 | case .basic:
20 | return makeNibView(name: "NativeAdView")
21 | case .card:
22 | return NativeAdCardView(frame: .zero)
23 | case .banner:
24 | return NativeAdBannerView(frame: .zero)
25 | case .largeBanner:
26 | return NativeLargeAdBannerView(frame: .zero)
27 | }
28 | }
29 |
30 | func makeNibView(name: String) -> GADNativeAdView {
31 | let bundle = Bundle.module
32 | let nib = UINib(nibName: name, bundle: bundle)
33 | return nib.instantiate(withOwner: nil, options: nil).first as! GADNativeAdView
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Native/NativeLargeAdBannerView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NativeBigAdBannerView.swift
3 | //
4 | //
5 | // Created by minghui on 2024/3/5.
6 | //
7 |
8 | import GoogleMobileAds
9 | import UIKit
10 | import LBTATools
11 |
12 | class NativeLargeAdBannerView: GADNativeAdView {
13 | // require
14 | let myMediaView = GADMediaView()
15 | let headlineLabel = UILabel(text: "", font: .systemFont(ofSize: 15, weight: .medium), textColor: .label, numberOfLines: 2)
16 | let adTag: UILabel = UILabel(text: "AD", font: .systemFont(ofSize: 10, weight: .semibold), textColor: .secondaryLabel, textAlignment: .center)
17 |
18 | // for web
19 | let advertiserLabel = UILabel(text: "", font: .systemFont(ofSize: 14, weight: .regular), textColor: .secondaryLabel, numberOfLines: 1)
20 | let bodyLabel = UILabel(text: "", font: .systemFont(ofSize: 14, weight: .regular), textColor: .secondaryLabel, numberOfLines: 3)
21 |
22 | // for app
23 | let callToActionButton = UIButton(title: "", titleColor: .label, font: .boldSystemFont(ofSize: 14), backgroundColor: .systemBlue, target: nil, action: nil)
24 |
25 | override init(frame: CGRect) {
26 | super.init(frame: frame)
27 | setupViews()
28 | }
29 |
30 | func setupViews() {
31 | // 設定 media view 的最小尺寸
32 | myMediaView.translatesAutoresizingMaskIntoConstraints = false
33 | myMediaView.widthAnchor.constraint(equalTo: myMediaView.heightAnchor, multiplier: 16/9).isActive = true
34 | myMediaView.contentMode = .scaleAspectFill
35 | myMediaView.clipsToBounds = true
36 | self.mediaView = myMediaView
37 |
38 | self.headlineView = headlineLabel
39 | self.advertiserView = advertiserLabel
40 | self.bodyView = bodyLabel
41 |
42 | callToActionButton.isUserInteractionEnabled = false
43 | callToActionButton.layer.cornerRadius = 8
44 | callToActionButton.clipsToBounds = true
45 | self.callToActionView = callToActionButton
46 |
47 | let leftStack = stack(headlineLabel, advertiserLabel, bodyLabel, callToActionButton).withMargins(.init(top: 8, left: 0, bottom: 8, right: 8))
48 |
49 | hstack(myMediaView,leftStack, spacing: 8)
50 |
51 | // AD Tag Label
52 | addSubview(adTag)
53 | adTag.translatesAutoresizingMaskIntoConstraints = false
54 | NSLayoutConstraint.activate([
55 | adTag.topAnchor.constraint(equalTo: topAnchor, constant: 4),
56 | adTag.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 4),
57 | adTag.widthAnchor.constraint(greaterThanOrEqualToConstant: 25),
58 | adTag.heightAnchor.constraint(equalToConstant: 15)
59 | ])
60 |
61 | adTag.backgroundColor = .systemFill
62 | adTag.layer.cornerRadius = 4
63 | adTag.clipsToBounds = true
64 | adTag.text = NSLocalizedString("AD", bundle: .module, comment: "Ad tag label")
65 | }
66 |
67 | required init?(coder aDecoder: NSCoder) {
68 | fatalError("init(coder:) has not been implemented")
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Resources/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Resources/Assets.xcassets/stars_3_5.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "stars_3_5.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Resources/Assets.xcassets/stars_3_5.imageset/stars_3_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dearhui/AdmobSwiftUI/f682a30867058d75899f3abc88b56d22a0c5bd96/Sources/AdmobSwiftUI/Resources/Assets.xcassets/stars_3_5.imageset/stars_3_5.png
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Resources/Assets.xcassets/stars_4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "stars_4.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Resources/Assets.xcassets/stars_4.imageset/stars_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dearhui/AdmobSwiftUI/f682a30867058d75899f3abc88b56d22a0c5bd96/Sources/AdmobSwiftUI/Resources/Assets.xcassets/stars_4.imageset/stars_4.png
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Resources/Assets.xcassets/stars_4_5.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "stars_4_5.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Resources/Assets.xcassets/stars_4_5.imageset/stars_4_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dearhui/AdmobSwiftUI/f682a30867058d75899f3abc88b56d22a0c5bd96/Sources/AdmobSwiftUI/Resources/Assets.xcassets/stars_4_5.imageset/stars_4_5.png
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Resources/Assets.xcassets/stars_5.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "stars_5.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Resources/Assets.xcassets/stars_5.imageset/stars_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dearhui/AdmobSwiftUI/f682a30867058d75899f3abc88b56d22a0c5bd96/Sources/AdmobSwiftUI/Resources/Assets.xcassets/stars_5.imageset/stars_5.png
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Resources/Info-demo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSUserTrackingUsageDescription
6 | DemoText
7 | GADApplicationIdentifier
8 | ca-app-pub-3940256099942544~1458002511
9 | SKAdNetworkItems
10 |
11 |
12 | SKAdNetworkIdentifier
13 | cstr6suwn9.skadnetwork
14 |
15 |
16 | SKAdNetworkIdentifier
17 | 4fzdc2evr5.skadnetwork
18 |
19 |
20 | SKAdNetworkIdentifier
21 | 4pfyvq9l8r.skadnetwork
22 |
23 |
24 | SKAdNetworkIdentifier
25 | 2fnua5tdw4.skadnetwork
26 |
27 |
28 | SKAdNetworkIdentifier
29 | ydx93a7ass.skadnetwork
30 |
31 |
32 | SKAdNetworkIdentifier
33 | 5a6flpkh64.skadnetwork
34 |
35 |
36 | SKAdNetworkIdentifier
37 | p78axxw29g.skadnetwork
38 |
39 |
40 | SKAdNetworkIdentifier
41 | v72qych5uu.skadnetwork
42 |
43 |
44 | SKAdNetworkIdentifier
45 | ludvb6z3bs.skadnetwork
46 |
47 |
48 | SKAdNetworkIdentifier
49 | cp8zw746q7.skadnetwork
50 |
51 |
52 | SKAdNetworkIdentifier
53 | c6k4g5qg8m.skadnetwork
54 |
55 |
56 | SKAdNetworkIdentifier
57 | s39g8k73mm.skadnetwork
58 |
59 |
60 | SKAdNetworkIdentifier
61 | 3qy4746246.skadnetwork
62 |
63 |
64 | SKAdNetworkIdentifier
65 | 3sh42y64q3.skadnetwork
66 |
67 |
68 | SKAdNetworkIdentifier
69 | f38h382jlk.skadnetwork
70 |
71 |
72 | SKAdNetworkIdentifier
73 | hs6bdukanm.skadnetwork
74 |
75 |
76 | SKAdNetworkIdentifier
77 | prcb7njmu6.skadnetwork
78 |
79 |
80 | SKAdNetworkIdentifier
81 | v4nxqhlyqp.skadnetwork
82 |
83 |
84 | SKAdNetworkIdentifier
85 | wzmmz9fp6w.skadnetwork
86 |
87 |
88 | SKAdNetworkIdentifier
89 | yclnxrl5pm.skadnetwork
90 |
91 |
92 | SKAdNetworkIdentifier
93 | t38b2kh725.skadnetwork
94 |
95 |
96 | SKAdNetworkIdentifier
97 | 7ug5zh24hu.skadnetwork
98 |
99 |
100 | SKAdNetworkIdentifier
101 | 9rd848q2bz.skadnetwork
102 |
103 |
104 | SKAdNetworkIdentifier
105 | y5ghdn5j9k.skadnetwork
106 |
107 |
108 | SKAdNetworkIdentifier
109 | n6fk4nfna4.skadnetwork
110 |
111 |
112 | SKAdNetworkIdentifier
113 | v9wttpbfk9.skadnetwork
114 |
115 |
116 | SKAdNetworkIdentifier
117 | n38lu8286q.skadnetwork
118 |
119 |
120 | SKAdNetworkIdentifier
121 | 47vhws6wlr.skadnetwork
122 |
123 |
124 | SKAdNetworkIdentifier
125 | kbd757ywx3.skadnetwork
126 |
127 |
128 | SKAdNetworkIdentifier
129 | 9t245vhmpl.skadnetwork
130 |
131 |
132 | SKAdNetworkIdentifier
133 | a2p9lx4jpn.skadnetwork
134 |
135 |
136 | SKAdNetworkIdentifier
137 | 22mmun2rn5.skadnetwork
138 |
139 |
140 | SKAdNetworkIdentifier
141 | 4468km3ulz.skadnetwork
142 |
143 |
144 | SKAdNetworkIdentifier
145 | 2u9pt9hc89.skadnetwork
146 |
147 |
148 | SKAdNetworkIdentifier
149 | 8s468mfl3y.skadnetwork
150 |
151 |
152 | SKAdNetworkIdentifier
153 | av6w8kgt66.skadnetwork
154 |
155 |
156 | SKAdNetworkIdentifier
157 | klf5c3l5u5.skadnetwork
158 |
159 |
160 | SKAdNetworkIdentifier
161 | ppxm28t8ap.skadnetwork
162 |
163 |
164 | SKAdNetworkIdentifier
165 | 424m5254lk.skadnetwork
166 |
167 |
168 | SKAdNetworkIdentifier
169 | ecpz2srf59.skadnetwork
170 |
171 |
172 | SKAdNetworkIdentifier
173 | uw77j35x4d.skadnetwork
174 |
175 |
176 | SKAdNetworkIdentifier
177 | mlmmfzh3r3.skadnetwork
178 |
179 |
180 | SKAdNetworkIdentifier
181 | 578prtvx9j.skadnetwork
182 |
183 |
184 | SKAdNetworkIdentifier
185 | 4dzt52r2t5.skadnetwork
186 |
187 |
188 | SKAdNetworkIdentifier
189 | gta9lk7p23.skadnetwork
190 |
191 |
192 | SKAdNetworkIdentifier
193 | e5fvkxwrpn.skadnetwork
194 |
195 |
196 | SKAdNetworkIdentifier
197 | 8c4e2ghe7u.skadnetwork
198 |
199 |
200 | SKAdNetworkIdentifier
201 | zq492l623r.skadnetwork
202 |
203 |
204 | SKAdNetworkIdentifier
205 | 3rd42ekr43.skadnetwork
206 |
207 |
208 | SKAdNetworkIdentifier
209 | 3qcr597p9d.skadnetwork
210 |
211 |
212 | NSAppTransportSecurity
213 |
214 | NSAllowsArbitraryLoads
215 |
216 | NSAllowsArbitraryLoadsForMedia
217 |
218 | NSAllowsArbitraryLoadsInWebContent
219 |
220 |
221 |
222 |
223 |
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Resources/Localizable.xcstrings:
--------------------------------------------------------------------------------
1 | {
2 | "sourceLanguage" : "en",
3 | "strings" : {
4 | "AD" : {
5 | "extractionState" : "manual",
6 | "localizations" : {
7 | "zh-Hant" : {
8 | "stringUnit" : {
9 | "state" : "translated",
10 | "value" : "廣告"
11 | }
12 | }
13 | }
14 | }
15 | },
16 | "version" : "1.0"
17 | }
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Resources/NativeXibs/NativeAdView.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
43 |
51 |
56 |
61 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
--------------------------------------------------------------------------------
/Sources/AdmobSwiftUI/Resources/NativeXibs/NativeAdViewDemo.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
43 |
50 |
56 |
62 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
--------------------------------------------------------------------------------
/Tests/AdmobSwiftUITests/AdmobSwiftUITests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import AdmobSwiftUI
3 |
4 | final class AdmobSwiftUITests: XCTestCase {
5 | func testExample() throws {
6 | // This is an example of a functional test case.
7 | // Use XCTAssert and related functions to verify your tests produce the correct
8 | // results.
9 | XCTAssertEqual(AdmobSwiftUI().text, "Hello, World!")
10 | }
11 | }
12 |
--------------------------------------------------------------------------------