diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/PluginDelegate.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/PluginDelegate.kt index 0c8aa45..460abb4 100644 --- a/android/src/main/kotlin/com/example/union_ad_ssgf/PluginDelegate.kt +++ b/android/src/main/kotlin/com/example/union_ad_ssgf/PluginDelegate.kt @@ -134,7 +134,6 @@ class PluginDelegate(var activity: Activity, bind: FlutterPluginBinding) : override fun onStartSuccess() { Log.e("gdt onStartSuccess", "加载成功") } - override fun onStartFailed(e: Exception) { Log.e("gdt onStartFailed:", e.toString()) } diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/page/AdSplashActivity.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/page/AdSplashActivity.kt index 07e9acd..7ab1858 100644 --- a/android/src/main/kotlin/com/example/union_ad_ssgf/page/AdSplashActivity.kt +++ b/android/src/main/kotlin/com/example/union_ad_ssgf/page/AdSplashActivity.kt @@ -25,20 +25,29 @@ import com.qq.e.comm.util.AdError */ class AdSplashActivity() : AppCompatActivity(), SplashADListener { private val TAG = AdSplashActivity::class.java.getSimpleName() - - // 广告容器 + /** + * 广告容器 + */ private var ad_container: FrameLayout? = null - // 自定义品牌 logo + /** + * 自定义品牌 logo + */ private var ad_logo: AppCompatImageView? = null - // 广告位 id + /** + * 广告位 id + */ private var posId: String? = null - // 是否全屏 + /** + * 是否全屏 + */ private var isFullScreen = false - // 开屏广告 + /** + * 开屏广告 + */ private var splashAD: SplashAD? = null override fun onCreate(savedInstanceState: Bundle?) { @@ -84,12 +93,18 @@ class AdSplashActivity() : AppCompatActivity(), SplashADListener { } } + /** + * 广告关闭时调用,可能是用户关闭或者展示时间到。此时一般需要跳过开屏的 Activity,进入应用内容页面 + */ override fun onADDismissed() { Log.d(TAG, "onADDismissed") finishPage() AdEventHandler.getInstance()?.sendEvent(AdEvent(posId, "", 1, AdEventAction.onAdClosed)); } + /** + * 广告加载或展示过程中出错,AdError中包含了错误码和错误描述,具体错误码内容可参考错误码部分 + */ override fun onNoAD(adError: AdError) { Log.d(TAG, "onNoAD adError:" + adError.errorMsg); finishPage() @@ -97,25 +112,41 @@ class AdSplashActivity() : AppCompatActivity(), SplashADListener { .sendEvent(AdErrorEvent(posId, "", 1, adError.errorCode, adError.errorMsg)); } + /** + * 广告成功展示时调用,成功展示不等于有效展示(比如广告容器高度不够) + */ override fun onADPresent() { Log.d(TAG, "onADPresent") AdEventHandler.getInstance()!!.sendEvent(AdEvent(posId, "", 1, AdEventAction.onAdPresent)) } + /** + * 广告被点击时调用,不代表满足计费条件(如点击时网络异常) + */ override fun onADClicked() { Log.d(TAG, "onADClicked") AdEventHandler.getInstance()!!.sendEvent(AdEvent(posId, "", 1, AdEventAction.onAdClicked)) } + /** + * 倒计时回调,返回广告还将被展示的剩余时间,单位是 ms + */ override fun onADTick(millisUntilFinished: Long) { Log.d(TAG, "onADTick millisUntilFinished:$millisUntilFinished"); } + /** + * 广告曝光时调用 + */ override fun onADExposure() { Log.d(TAG, "onADExposure") AdEventHandler.getInstance()!!.sendEvent(AdEvent(posId, "", 1, AdEventAction.onAdExposure)) } + /** + * 广告加载成功的回调,在fetchAdOnly的情况下,表示广告拉取成功可以显示了。 + * 广告需要在SystemClock.elapsedRealtime 4.15.10) + +DEPENDENCIES: + - Flutter (from `Flutter`) + - integration_test (from `.symlinks/plugins/integration_test/ios`) + - union_ad_ssgf (from `.symlinks/plugins/union_ad_ssgf/ios`) + +SPEC REPOS: + trunk: + - GDTMobSDK + +EXTERNAL SOURCES: + Flutter: + :path: Flutter + integration_test: + :path: ".symlinks/plugins/integration_test/ios" + union_ad_ssgf: + :path: ".symlinks/plugins/union_ad_ssgf/ios" + +SPEC CHECKSUMS: + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + GDTMobSDK: 71e264496ba2ade7d9ce528f4eba1a5424a86654 + integration_test: ce0a3ffa1de96d1a89ca0ac26fca7ea18a749ef4 + union_ad_ssgf: d55f20ec32899cdfba0eae257331e3f9a01ee366 + +PODFILE CHECKSUM: 7be2f5f74864d463a8ad433546ed1de7e0f29aef + +COCOAPODS: 1.15.2 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 349e17c..26ddfc8 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -14,6 +14,8 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + D5039791B51B519AA9AA2312 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 231BE3EF9C3C195F1B2CF5CB /* Pods_Runner.framework */; settings = {ATTRIBUTES = (Required, ); }; }; + D7B10491D9BF83EA9C67A5DD /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD72858EA9974C84863383E0 /* Pods_RunnerTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -42,12 +44,38 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 231BE3EF9C3C195F1B2CF5CB /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 3C501DB22CC78D0000708F60 /* GDTAdParams.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDTAdParams.h; sourceTree = ""; }; + 3C501DB32CC78D0000708F60 /* GDTAdProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDTAdProtocol.h; sourceTree = ""; }; + 3C501DB42CC78D0000708F60 /* GDTAdTestSetting.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDTAdTestSetting.h; sourceTree = ""; }; + 3C501DB52CC78D0000708F60 /* GDTLoadAdParams.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDTLoadAdParams.h; sourceTree = ""; }; + 3C501DB62CC78D0000708F60 /* GDTLogoView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDTLogoView.h; sourceTree = ""; }; + 3C501DB72CC78D0000708F60 /* GDTMediaView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDTMediaView.h; sourceTree = ""; }; + 3C501DB82CC78D0000708F60 /* GDTNativeExpressAd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDTNativeExpressAd.h; sourceTree = ""; }; + 3C501DB92CC78D0000708F60 /* GDTNativeExpressAdView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDTNativeExpressAdView.h; sourceTree = ""; }; + 3C501DBA2CC78D0000708F60 /* GDTPrivacyConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDTPrivacyConfiguration.h; sourceTree = ""; }; + 3C501DBB2CC78D0000708F60 /* GDTRewardVideoAd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDTRewardVideoAd.h; sourceTree = ""; }; + 3C501DBC2CC78D0000708F60 /* GDTSDKConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDTSDKConfig.h; sourceTree = ""; }; + 3C501DBD2CC78D0000708F60 /* GDTSDKDefines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDTSDKDefines.h; sourceTree = ""; }; + 3C501DBE2CC78D0000708F60 /* GDTServerSideVerificationOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDTServerSideVerificationOptions.h; sourceTree = ""; }; + 3C501DBF2CC78D0000708F60 /* GDTSplashAd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDTSplashAd.h; sourceTree = ""; }; + 3C501DC02CC78D0000708F60 /* GDTUnifiedBannerView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDTUnifiedBannerView.h; sourceTree = ""; }; + 3C501DC12CC78D0000708F60 /* GDTUnifiedInterstitialAd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDTUnifiedInterstitialAd.h; sourceTree = ""; }; + 3C501DC22CC78D0000708F60 /* GDTUnifiedNativeAd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDTUnifiedNativeAd.h; sourceTree = ""; }; + 3C501DC32CC78D0000708F60 /* GDTUnifiedNativeAdDataObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDTUnifiedNativeAdDataObject.h; sourceTree = ""; }; + 3C501DC42CC78D0000708F60 /* GDTUnifiedNativeAdView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDTUnifiedNativeAdView.h; sourceTree = ""; }; + 3C501DC52CC78D0000708F60 /* GDTVideoAdReporter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDTVideoAdReporter.h; sourceTree = ""; }; + 3C501DC62CC78D0000708F60 /* GDTVideoConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDTVideoConfig.h; sourceTree = ""; }; + 3C501DC72CC78D0000708F60 /* libGDTMobSDK.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libGDTMobSDK.a; sourceTree = ""; }; + 63E46DBB6AEAA1CBF6915B40 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 7F5B62B557E07ABCC2F06213 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 8A89FE40B60941BB6FEE77D8 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -55,13 +83,26 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + A75FF7AEFE9DC4A76368F956 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + BEC41ED0E4105D18DE067E73 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + DD72858EA9974C84863383E0 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F3A96745EDBF35DB29565948 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 2CC9710731FB2B6942762B9C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D7B10491D9BF83EA9C67A5DD /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EB1CF9000F007C117D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D5039791B51B519AA9AA2312 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -76,6 +117,57 @@ path = RunnerTests; sourceTree = ""; }; + 354765ABE2C866D39CE73987 /* Pods */ = { + isa = PBXGroup; + children = ( + 63E46DBB6AEAA1CBF6915B40 /* Pods-Runner.debug.xcconfig */, + A75FF7AEFE9DC4A76368F956 /* Pods-Runner.release.xcconfig */, + 7F5B62B557E07ABCC2F06213 /* Pods-Runner.profile.xcconfig */, + F3A96745EDBF35DB29565948 /* Pods-RunnerTests.debug.xcconfig */, + 8A89FE40B60941BB6FEE77D8 /* Pods-RunnerTests.release.xcconfig */, + BEC41ED0E4105D18DE067E73 /* Pods-RunnerTests.profile.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; + 3C501DC82CC78D0000708F60 /* lib */ = { + isa = PBXGroup; + children = ( + 3C501DB22CC78D0000708F60 /* GDTAdParams.h */, + 3C501DB32CC78D0000708F60 /* GDTAdProtocol.h */, + 3C501DB42CC78D0000708F60 /* GDTAdTestSetting.h */, + 3C501DB52CC78D0000708F60 /* GDTLoadAdParams.h */, + 3C501DB62CC78D0000708F60 /* GDTLogoView.h */, + 3C501DB72CC78D0000708F60 /* GDTMediaView.h */, + 3C501DB82CC78D0000708F60 /* GDTNativeExpressAd.h */, + 3C501DB92CC78D0000708F60 /* GDTNativeExpressAdView.h */, + 3C501DBA2CC78D0000708F60 /* GDTPrivacyConfiguration.h */, + 3C501DBB2CC78D0000708F60 /* GDTRewardVideoAd.h */, + 3C501DBC2CC78D0000708F60 /* GDTSDKConfig.h */, + 3C501DBD2CC78D0000708F60 /* GDTSDKDefines.h */, + 3C501DBE2CC78D0000708F60 /* GDTServerSideVerificationOptions.h */, + 3C501DBF2CC78D0000708F60 /* GDTSplashAd.h */, + 3C501DC02CC78D0000708F60 /* GDTUnifiedBannerView.h */, + 3C501DC12CC78D0000708F60 /* GDTUnifiedInterstitialAd.h */, + 3C501DC22CC78D0000708F60 /* GDTUnifiedNativeAd.h */, + 3C501DC32CC78D0000708F60 /* GDTUnifiedNativeAdDataObject.h */, + 3C501DC42CC78D0000708F60 /* GDTUnifiedNativeAdView.h */, + 3C501DC52CC78D0000708F60 /* GDTVideoAdReporter.h */, + 3C501DC62CC78D0000708F60 /* GDTVideoConfig.h */, + 3C501DC72CC78D0000708F60 /* libGDTMobSDK.a */, + ); + path = lib; + sourceTree = ""; + }; + 3C501DC92CC78D0000708F60 /* GDTMobSDK */ = { + isa = PBXGroup; + children = ( + 3C501DC82CC78D0000708F60 /* lib */, + ); + name = GDTMobSDK; + path = Pods/GDTMobSDK; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -90,10 +182,13 @@ 97C146E51CF9000F007C117D = { isa = PBXGroup; children = ( + 3C501DC92CC78D0000708F60 /* GDTMobSDK */, 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 331C8082294A63A400263BE5 /* RunnerTests */, + 354765ABE2C866D39CE73987 /* Pods */, + F69892A496D5EE722DDD9613 /* Frameworks */, ); sourceTree = ""; }; @@ -121,6 +216,15 @@ path = Runner; sourceTree = ""; }; + F69892A496D5EE722DDD9613 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 231BE3EF9C3C195F1B2CF5CB /* Pods_Runner.framework */, + DD72858EA9974C84863383E0 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -128,8 +232,10 @@ isa = PBXNativeTarget; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( + 8593B862DB554AA0EEF8219B /* [CP] Check Pods Manifest.lock */, 331C807D294A63A400263BE5 /* Sources */, 331C807F294A63A400263BE5 /* Resources */, + 2CC9710731FB2B6942762B9C /* Frameworks */, ); buildRules = ( ); @@ -145,12 +251,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + 4AC0BF70F33FC1FE2306EF33 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + D172DAC651DB5E4F39461CF2 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -236,7 +344,51 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n"; + }; + 4AC0BF70F33FC1FE2306EF33 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 8593B862DB554AA0EEF8219B /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; @@ -253,6 +405,23 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + D172DAC651DB5E4F39461CF2 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -379,6 +548,7 @@ }; 331C8088294A63A400263BE5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = F3A96745EDBF35DB29565948 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -396,6 +566,7 @@ }; 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 8A89FE40B60941BB6FEE77D8 /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -411,6 +582,7 @@ }; 331C808A294A63A400263BE5 /* Profile */ = { isa = XCBuildConfiguration; + baseConfigurationReference = BEC41ED0E4105D18DE067E73 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; diff --git a/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..b3acb49 100644 --- a/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,10 @@ + + + + diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift index 9074fee..1cdebbf 100644 --- a/example/ios/Runner/AppDelegate.swift +++ b/example/ios/Runner/AppDelegate.swift @@ -2,7 +2,7 @@ import Flutter import UIKit @UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { +@objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? diff --git a/example/ios/Runner/Base.lproj/Main.storyboard b/example/ios/Runner/Base.lproj/Main.storyboard index f3c2851..b263922 100644 --- a/example/ios/Runner/Base.lproj/Main.storyboard +++ b/example/ios/Runner/Base.lproj/Main.storyboard @@ -1,8 +1,10 @@ - - + + + - + + @@ -14,13 +16,14 @@ - + - + + diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index 5ac2efb..29d54ff 100644 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - Union Ad Ssgf + UnionAdSsgf CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -24,6 +24,13 @@ $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + NSUserTrackingUsageDescription + 为了向您提供更优质、安全的个性化服务及内容,需要您允许使用相关权限 UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -41,6 +48,8 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + UIViewControllerBasedStatusBarAppearance + CADisableMinimumFrameDurationOnPhone UIApplicationSupportsIndirectInputEvents diff --git a/example/ios/Runner/Runner-Bridging-Header.h b/example/ios/Runner/Runner-Bridging-Header.h index 308a2a5..7c3b3a5 100644 --- a/example/ios/Runner/Runner-Bridging-Header.h +++ b/example/ios/Runner/Runner-Bridging-Header.h @@ -1 +1,8 @@ #import "GeneratedPluginRegistrant.h" +#import "GDTNativeExpressAdView.h" +#import "GDTNativeExpressAd.h" +#import "GDTSplashAd.h" +#import "GDTRewardVideoAd.h" +#import "GDTSDKConfig.h" + + diff --git a/example/lib/home_page.dart b/example/lib/home_page.dart index 146a92a..cf6aada 100644 --- a/example/lib/home_page.dart +++ b/example/lib/home_page.dart @@ -33,28 +33,28 @@ class _HomePageState extends State { padding: const EdgeInsets.all(10), child: Column( children: [ - SizedBox(height: 10), + const SizedBox(height: 10), Text('Result: $_result'), - SizedBox(height: 10), + const SizedBox(height: 10), Text('onAdEvent: $_adEvent'), - SizedBox(height: 20), + const SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ ElevatedButton( - child: Text('初始化'), + child: const Text('初始化'), onPressed: () {}, ), - SizedBox(height: 20), + const SizedBox(height: 20), ElevatedButton( - child: Text('请求跟踪授权'), + child: const Text('请求跟踪授权'), onPressed: () { requestIDFA(); }, ), - SizedBox(height: 20), + const SizedBox(height: 20), ElevatedButton( - child: Text('个性化广告'), + child: const Text('个性化广告'), onPressed: () { setPersonalizedAd(1); }, @@ -65,14 +65,12 @@ class _HomePageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ ElevatedButton( - child: Text('开屏(Logo2)'), - onPressed: () { - showSplashAd(AdsConfig.logo2); - }, + child: const Text('开屏(Logo2)'), + onPressed: () {}, ), - SizedBox(height: 20), + const SizedBox(height: 20), ElevatedButton( - child: Text('开屏(全屏)'), + child: const Text('开屏(全屏)'), onPressed: () { showSplashAd(); setState(() {}); @@ -84,14 +82,14 @@ class _HomePageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ ElevatedButton( - child: Text('插屏广告'), + child: const Text('插屏广告'), onPressed: () { showInterstitialAd(AdsConfig.interstitialId); }, ), - SizedBox(height: 20), + const SizedBox(height: 20), ElevatedButton( - child: Text('插全屏广告'), + child: const Text('插全屏广告'), onPressed: () { showInterstitialAd( AdsConfig.interstitialFullScreenVideoId, @@ -105,7 +103,7 @@ class _HomePageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ ElevatedButton( - child: Text('插屏激励'), + child: const Text('插屏激励'), onPressed: () { showInterstitialAd( AdsConfig.interstitialRewardVideoId, @@ -114,27 +112,26 @@ class _HomePageState extends State { ); }, ), - SizedBox(height: 20), + const SizedBox(height: 20), ElevatedButton( - child: Text('激励视频'), + child: const Text('激励视频'), onPressed: () { showRewardVideoAd(); }, ), ], ), - SizedBox(height: 20), + const SizedBox(height: 20), ElevatedButton( - child: Text('信息流'), + child: const Text('信息流'), onPressed: () { // Navigator.push( // context, // MaterialPageRoute( - // builder: (context) => FeedPage(), - // )); + // builder: (context) => FeedPage(),)); }, ), - SizedBox(height: 20), + const SizedBox(height: 20), const Center(child: Text('👇🏻 Banner 广告 👇🏻')), const SizedBox(height: 10), // AdBannerWidget( @@ -144,7 +141,7 @@ class _HomePageState extends State { // interval: 0, // show: true, // ), - SizedBox(height: 10), + const SizedBox(height: 10), ], ), ), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index ca3c88a..44ba26e 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -3,6 +3,7 @@ description: "Demonstrates how to use the union_ad_ssgf plugin." # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. publish_to: 'none' # Remove this line if you wish to publish to pub.dev +version: 0.0.001+001 environment: sdk: '>=3.4.4 <4.0.0' @@ -28,6 +29,7 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.6 + loadany: ^1.0.0 dev_dependencies: integration_test: @@ -52,7 +54,9 @@ flutter: # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true - + + assets: + - images/ # To add assets to your application, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg diff --git a/ios/Classes/Event/FAQAdErrorEvent.swift b/ios/Classes/Event/FAQAdErrorEvent.swift new file mode 100644 index 0000000..ed12de5 --- /dev/null +++ b/ios/Classes/Event/FAQAdErrorEvent.swift @@ -0,0 +1,32 @@ +// +// FAQAdErrorEvent.swift +// Pods +// +// Created by Jin on 10/23/24. +// +import Foundation + +// 广告错误事件 +class FAQAdErrorEvent: FAQAdEvent { + // 错误码 + var errCode: NSNumber + + // 错误信息 + var errMsg: String + + // 构造广告错误事件 + init(adId: String, errCode: NSNumber, errMsg: String) { + self.errCode = errCode + self.errMsg = errMsg + super.init(adId: adId, action: "onAdError") // 假设 onAdError 是一个字符串 + } + + // 转换为字典 + override func toMap() -> [String: Any] { + var errData = super.toMap() // 获取父类字典 + errData["errCode"] = errCode // 添加错误代码 + errData["errMsg"] = errMsg // 添加错误信息 + return errData // 返回完整的字典 + } +} + diff --git a/ios/Classes/Event/FAQAdEvent.swift b/ios/Classes/Event/FAQAdEvent.swift new file mode 100644 index 0000000..b892eab --- /dev/null +++ b/ios/Classes/Event/FAQAdEvent.swift @@ -0,0 +1,27 @@ +// +// FAQAdEvent.swift +// Pods +// +// Created by Jin on 10/23/24. +// + +import Foundation + +// 通知 +class FAQAdEvent { + // 广告 id + var adId: String + // 操作 + var action: String + + // 初始化方法 - 构造广告事件 + init(adId: String, action: String) { + self.adId = adId + self.action = action + } + + // 转换为 Map 操作 + func toMap() -> [String: Any] { + return ["adId": adId, "action": action] + } +} diff --git a/ios/Classes/Event/FAQAdEventAction.swift b/ios/Classes/Event/FAQAdEventAction.swift new file mode 100644 index 0000000..24160c1 --- /dev/null +++ b/ios/Classes/Event/FAQAdEventAction.swift @@ -0,0 +1,43 @@ +// +// FAQAdEventAction.swift +// Pods +// +// Created by Jin on 10/23/24. +// + +import Foundation + +//广告事件操作常量 + +// 广告错误 +let onAdError = "onAdError" + +// 广告加载成功 +let onAdLoaded = "onAdLoaded" + +// 广告填充 +let onAdPresent = "onAdPresent" + +// 广告曝光 +let onAdExposure = "onAdExposure" + +// 广告关闭(计时结束或者用户点击关闭) +let onAdClosed = "onAdClosed" + +// 广告点击 +let onAdClicked = "onAdClicked" + +// 广告跳过 +let onAdSkip = "onAdSkip" + +// 广告播放或计时完毕 +let onAdComplete = "onAdComplete" + +// 获得广告激励 +let onAdReward = "onAdReward" + +// 广告事件操作类 +class FAQAdEventAction: NSObject { + // 可以在此处添加广告事件操作的方法 +} + diff --git a/ios/Classes/Event/FAQAdRewardEvent.swift b/ios/Classes/Event/FAQAdRewardEvent.swift new file mode 100644 index 0000000..e5f9084 --- /dev/null +++ b/ios/Classes/Event/FAQAdRewardEvent.swift @@ -0,0 +1,36 @@ +// +// FAQAdRewardEvent.swift +// Pods +// +// Created by Jin on 10/23/24. +// + +import Foundation + +// 广告激励事件 +class FAQAdRewardEvent: FAQAdEvent { + // 服务端验证唯一id + var transId: String + // 服务端验证的自定义信息 + var customData: String + // 服务端验证的用户信息 + var userId: String + + // 构造广告激励事件 + init(adId: String, transId: String, customData: String, userId: String) { + self.transId = transId + self.customData = customData + self.userId = userId + super.init(adId: adId, action: onAdReward) // 假设 onAdReward 是一个常量 + } + + // 转换为字典 + override func toMap() -> [String: Any] { + var errData = super.toMap() // 获取父类字典 + errData["transId"] = transId // 添加 transId + errData["customData"] = customData // 添加 customData + errData["userId"] = userId // 添加 userId + return errData // 返回完整的字典 + } +} + diff --git a/ios/Classes/Page/FAQBaseAdPage.swift b/ios/Classes/Page/FAQBaseAdPage.swift new file mode 100644 index 0000000..e2f5d51 --- /dev/null +++ b/ios/Classes/Page/FAQBaseAdPage.swift @@ -0,0 +1,78 @@ +// +// FAQBaseAdPage.swift +// Pods +// +// Created by Jin on 10/23/24. +// + +import Flutter +import UIKit + +// 基础 - 广告页面 +class FAQBaseAdPage: NSObject { + let kPosId = "posId" + + var posId: String! + var eventSink: FlutterEventSink? + var mainWin: UIWindow? + var rootController: UIViewController? + var width: CGFloat = 0 + var height: CGFloat = 0 + + // 添加广告事件 + func addAdEvent(_ event: FAQAdEvent) { + if let eventSink = self.eventSink { + eventSink(event.toMap()) + } + } + + // 显示广告 + func showAd(call: FlutterMethodCall, eventSink: @escaping FlutterEventSink) { + guard let arguments = call.arguments as? [String: Any], + let posId = arguments[kPosId] as? String + else { + return + } + + self.posId = posId + self.eventSink = eventSink + + // 获取主 window + self.mainWin = UIApplication.shared.keyWindow + + // 获取 rootViewController + self.rootController = self.mainWin?.rootViewController + + // 获取宽高 + let size = UIScreen.main.bounds.size + self.width = size.width + self.height = size.height + + loadAd(call: call) + } + + // 加载广告 + func loadAd(call: FlutterMethodCall) { + print(#function) // 使用 Swift 的 print 代替 NSLog + } + + // 发送广告事件 + func sendEvent(_ event: FAQAdEvent) { + if let eventSink = self.eventSink { + eventSink(event.toMap()) + } + } + + // 发送广告事件 + func sendEventAction(_ action: String) { + let event = FAQAdEvent(adId: self.posId, action: action) + sendEvent(event) + } + + // 发送广告错误事件 + func sendErrorEvent(errCode: Int, errMsg: String) { + let event = FAQAdErrorEvent( + adId: self.posId, errCode: NSNumber(value: errCode), errMsg: errMsg) + sendEvent(event) + } +} diff --git a/ios/Classes/Page/FAQRewardVideoPage.swift b/ios/Classes/Page/FAQRewardVideoPage.swift new file mode 100644 index 0000000..4cc258f --- /dev/null +++ b/ios/Classes/Page/FAQRewardVideoPage.swift @@ -0,0 +1,108 @@ +// +// FAQRewardVideoPage.swift +// Pods +// +// Created by Jin on 10/23/24. +// + +import UIKit +import Flutter + +// 激励视频页面 +class FAQRewardVideoPage: FAQBaseAdPage, GDTRewardedVideoAdDelegate { + // 激励视频广告对象 + var rvad: GDTRewardVideoAd? + // 服务端验证的自定义信息 + var customData: String? + // 服务端验证的用户信息 + var userId: String? + + // 加载广告 + override func loadAd(call: FlutterMethodCall) { + guard let arguments = call.arguments as? [String: Any], + let customData = arguments["customData"] as? String, + let userId = arguments["userId"] as? String, + let playMuted = arguments["playMuted"] as? Bool else { + return + } + + self.customData = customData + self.userId = userId + + // 初始化激励视频广告 + self.rvad = GDTRewardVideoAd(placementId: self.posId) + self.rvad?.delegate = self + self.rvad?.videoMuted = playMuted + + // 如果设置了服务端验证,可以设置 serverSideVerificationOptions 属性 + let ssv = GDTServerSideVerificationOptions() + ssv.userIdentifier = self.userId + ssv.customRewardString = self.customData + self.rvad?.serverSideVerificationOptions = ssv + self.rvad?.load() + } + + // MARK: - GDTRewardVideoAdDelegate + + func gdt_rewardVideoAdDidLoad(_ rewardedVideoAd: GDTRewardVideoAd) { + print(#function) + if let controller = UIApplication.shared.keyWindow?.rootViewController { + self.rvad?.show(fromRootViewController: controller) + // 发送广告事件 + self.sendEventAction(onAdLoaded) + } + } + + func gdt_rewardVideoAdVideoDidLoad(_ rewardedVideoAd: GDTRewardVideoAd) { + print(#function) + } + + func gdt_rewardVideoAdWillVisible(_ rewardedVideoAd: GDTRewardVideoAd) { + print(#function) + // 发送广告事件 + self.sendEventAction(onAdPresent) + } + + func gdt_rewardVideoAdDidExposed(_ rewardedVideoAd: GDTRewardVideoAd) { + print(#function) + print("广告已曝光") + // 发送广告事件 + self.sendEventAction(onAdExposure) + } + + func gdt_rewardVideoAdDidClose(_ rewardedVideoAd: GDTRewardVideoAd) { + print(#function) + print("广告已关闭") + // 发送广告事件 + self.sendEventAction(onAdClosed) + } + + func gdt_rewardVideoAdDidClicked(_ rewardedVideoAd: GDTRewardVideoAd) { + print(#function) + print("广告已点击") + // 发送广告事件 + self.sendEventAction(onAdClicked) + } + + func gdt_rewardVideoAd(_ rewardedVideoAd: GDTRewardVideoAd, didFailWithError error: Error) { + print(#function) + print("ERROR: \(error.localizedDescription)") + // 发送广告错误事件 + self.sendErrorEvent(errCode: (error as NSError).code, errMsg: error.localizedDescription) + } + + func gdt_rewardVideoAdDidRewardEffective(_ rewardedVideoAd: GDTRewardVideoAd, info: [AnyHashable: Any]) { + print(#function) + if let transId = info["GDT_TRANS_ID"] as? String { + print("播放达到激励条件 transid: \(transId)") + // 发送激励事件 + let event = FAQAdRewardEvent(adId: self.posId, transId: transId, customData: self.customData!, userId: self.userId!) + self.sendEvent(event) + } + } + + func gdt_rewardVideoAdDidPlayFinish(_ rewardedVideoAd: GDTRewardVideoAd) { + print(#function) + print("视频播放结束") + } +} diff --git a/ios/Classes/Page/FAQSplashPage.swift b/ios/Classes/Page/FAQSplashPage.swift new file mode 100644 index 0000000..f51fa1b --- /dev/null +++ b/ios/Classes/Page/FAQSplashPage.swift @@ -0,0 +1,136 @@ +// +// FAQSplashPage.swift +// Pods +// +// Created by Jin on 10/23/24. +// + +import UIKit +import Flutter + +class FAQSplashPage: FAQBaseAdPage, GDTSplashAdDelegate { + var splashAd: GDTSplashAd! + var fullScreenAd: Bool = false + var bottomView: UIView? + + // 加载广告 + override func loadAd(call: FlutterMethodCall) { + // 获取 logo 和 fetchDelay + guard let arguments = call.arguments as? [String: Any], + let logo = arguments["logo"] as? String, + let fetchDelay = arguments["fetchDelay"] as? CGFloat + else { + return + } + + // logo 判断为空,则全屏展示 + self.fullScreenAd = logo.isEmpty + + // 初始化开屏广告 + self.splashAd = GDTSplashAd(placementId: self.posId) + // 确保 FAQSplashPage 遵循适当的协议 + self.splashAd.delegate = self + // 设置超时时长 + self.splashAd.fetchDelay = fetchDelay + + // 加载全屏广告 + if self.fullScreenAd { + self.splashAd.loadFullScreenAd() + } else { + // 加载半屏广告 + self.splashAd.load() + // 设置底部 logo + self.bottomView = nil + let size = UIScreen.main.bounds.size + let width = size.width + // 这里按照 15% 进行 logo 的展示 + let height: CGFloat = 112.5 + self.bottomView = UIView(frame: CGRect(x: 0, y: 0, width: width, height: height)) + self.bottomView?.backgroundColor = .white + if let logoImage = UIImage(named: logo) { + let logoView = UIImageView(image: logoImage) + logoView.frame = CGRect(x: 0, y: 0, width: width, height: height) + logoView.contentMode = .center + logoView.center = self.bottomView!.center + self.bottomView?.addSubview(logoView) + } + } + } + + // MARK: - GDTSplashAdDelegate + func splashAdDidLoad(_ splashAd: GDTSplashAd) { + print("splashAdDidLoad") + if let mainWindow = UIApplication.shared.keyWindow { + // 加载全屏广告 + if self.fullScreenAd { + self.splashAd.showFullScreenAd(in: mainWindow, withLogoImage: nil, skip: nil) + } else { + // 加载半屏广告 + self.splashAd.show(in: mainWindow, withBottomView: self.bottomView, skip: nil) + } + // 发送广告事件 + sendEventAction("onAdLoaded") + } + } + + func splashAdSuccessPresentScreen(_ splashAd: GDTSplashAd) { + print(#function) + // 发送广告事件 + sendEventAction("onAdPresent") + } + + func splashAdFail(toPresent splashAd: GDTSplashAd, withError error: Error) { + print("\( #function) \(error.localizedDescription)") + // 发送广告错误事件 + sendErrorEvent(error._code, withErrMsg: error.localizedDescription) + } + + func splashAdExposured(_ splashAd: GDTSplashAd) { + print(#function) + // 发送广告事件 + sendEventAction("onAdExposure") + } + + func splashAdClicked(_ splashAd: GDTSplashAd) { + print(#function) + // 发送广告事件 + sendEventAction("onAdClicked") + } + + func splashAdApplicationWillEnterBackground(_ splashAd: GDTSplashAd) { + print(#function) + } + + func splashAdWillClosed(_ splashAd: GDTSplashAd) { + print(#function) + } + + func splashAdClosed(_ splashAd: GDTSplashAd) { + print(#function) + self.splashAd = nil + // 发送广告事件 + sendEventAction("onAdClosed") + } + + func splashAdWillPresentFullScreenModal(_ splashAd: GDTSplashAd) { + print(#function) + } + + func splashAdDidPresentFullScreenModal(_ splashAd: GDTSplashAd) { + print(#function) + } + + func splashAdWillDismissFullScreenModal(_ splashAd: GDTSplashAd) { + print(#function) + } + + func splashAdDidDismissFullScreenModal(_ splashAd: GDTSplashAd) { + print(#function) + } + + // 发送错误事件的示例方法 + private func sendErrorEvent(_ code: Int, withErrMsg msg: String) { + // 实现发送错误事件的逻辑 + print("Error sent: \(code); message: \(msg)") + } +} diff --git a/ios/Classes/UnionAdSsgf-Bridging-Header.h b/ios/Classes/UnionAdSsgf-Bridging-Header.h new file mode 100644 index 0000000..90ebc83 --- /dev/null +++ b/ios/Classes/UnionAdSsgf-Bridging-Header.h @@ -0,0 +1,5 @@ +#import +#import +#import +#import +#import diff --git a/ios/Classes/UnionAdSsgfPlugin.swift b/ios/Classes/UnionAdSsgfPlugin.swift index 7750e3f..a3009ce 100644 --- a/ios/Classes/UnionAdSsgfPlugin.swift +++ b/ios/Classes/UnionAdSsgfPlugin.swift @@ -1,19 +1,115 @@ -import Flutter import UIKit +import Flutter -public class UnionAdSsgfPlugin: NSObject, FlutterPlugin { +public class UnionAdSsgfPlugin: NSObject, FlutterPlugin ,FlutterStreamHandler{ + static var methodName:String = "union_ad_ssgf_method" + static var eventName :String = "flutter_qq_ads_event" + var splashAd: FAQSplashPage! + var rewardAd: FAQRewardVideoPage! + + // 通知时间 + var eventChannel:FlutterEventChannel? + var sink:FlutterEventSink? + + public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { + self.sink = events; + return nil; + } + + public func onCancel(withArguments arguments: Any?) -> FlutterError? { + self.sink = nil; + return nil; + } + public static func register(with registrar: FlutterPluginRegistrar) { - let channel = FlutterMethodChannel(name: "union_ad_ssgf_method", binaryMessenger: registrar.messenger()) - let instance = UnionAdSsgfPlugin() - registrar.addMethodCallDelegate(instance, channel: channel) + let methodChannel = FlutterMethodChannel(name: methodName, binaryMessenger: registrar.messenger()); + let eventChannel = FlutterEventChannel(name: eventName, binaryMessenger: registrar.messenger()); + let instance = UnionAdSsgfPlugin(); + registrar.addMethodCallDelegate(instance, channel: methodChannel); + eventChannel.setStreamHandler(instance); } public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { case "getPlatformVersion": - result("iOS " + UIDevice.current.systemVersion) + getPlatformVersion(call: call, result: result) + case "initAd": // 初始化 + initAd(call:call, result: result); + case "setPersonalizedState": // 设置广告个性化 + setPersonalizedState(call:call, result: result); + case "showSplashAd": // 开屏广告 + showSplashAd(call:call, result: result); + case "showRewardVideoAd": // 激励广告 + showRewardVideoAd(call:call, result: result); default: result(FlutterMethodNotImplemented) } } + + // 版本号 + public func getPlatformVersion(call: FlutterMethodCall, result: @escaping FlutterResult) { + result("iOS " + UIDevice.current.systemVersion) + } + + // 初始化广告 + public func initAd(call: FlutterMethodCall, result: @escaping FlutterResult) { + if let arguments = call.arguments as? [String: Any], + let appId = arguments["appId"] as? String { + print("App ID: \(appId)") + // 初始化插件 + let initSuccess = GDTSDKConfig.initWithAppId(appId) + result(NSNumber(value: initSuccess)) + GDTSDKConfig.start {success, error in + // 返回结果 + result(true) + if success { + result(NSNumber(value: true)) + } else { + result(NSNumber(value: false)) + if let error = error { + print("FlutterQqAdsPlugin initAd error: \(error.localizedDescription)") + } + } + } + } else { + print("appId not found or invalid type.") + result(NSNumber(value: false)) // 处理无效的 appId + } + } + + // 设置广告个性化 + public func setPersonalizedState(call: FlutterMethodCall, result: @escaping FlutterResult) { + if let arguments = call.arguments as? [String: Any], + let state = arguments["state"] as? Int { + print("Set State : \(state)") + GDTSDKConfig.setPersonalizedState(state) + result(NSNumber(value: true)) + } else { + print("appId not found or invalid type.") + result(NSNumber(value: false)) // 处理无效的 appId + } + } + + // 开屏广告 + public func showSplashAd(call: FlutterMethodCall, result: FlutterResult) { + // 初始化 FAQSplashPage 实例 + self.splashAd = FAQSplashPage() + + // 调用 showAd 方法 + self.splashAd.showAd(call: call, eventSink: self.sink!) + + // 返回结果 + result(NSNumber(value: true)) + + } + + // 激励广告 + public func showRewardVideoAd(call: FlutterMethodCall, result: FlutterResult) { + // 初始化 FAQRewardVideoPage 实例 + self.rewardAd = FAQRewardVideoPage(); + // 调用 showAd 方法 + self.rewardAd.showAd(call: call, eventSink: self.sink!) + // 返回结果 + result(NSNumber(value: true)) + } } diff --git a/ios/union_ad_ssgf.podspec b/ios/union_ad_ssgf.podspec index 5bfacd8..b6c0e63 100644 --- a/ios/union_ad_ssgf.podspec +++ b/ios/union_ad_ssgf.podspec @@ -3,21 +3,58 @@ # Run `pod lib lint union_ad_ssgf.podspec` to validate before publishing. # Pod::Spec.new do |s| + # 库的名称 s.name = 'union_ad_ssgf' + # 库的版本号 s.version = '0.0.1' - s.summary = 'A new Flutter project.' + # 库的简要描述 + s.summary = '一款优质的 Flutter 广告插件(腾讯广告、广点通、优量汇)' + # 库的详细描述 s.description = <<-DESC -A new Flutter project. + 一款优质的 Flutter 广告插件(腾讯广告、广点通、优量汇). DESC s.homepage = 'http://example.com' + # 库的许可证类型和文件路径 s.license = { :file => '../LICENSE' } + + # 库的作者姓名和电子邮件 s.author = { 'Your Company' => 'email@example.com' } + # 库的源代码位置,可以是Git仓库的URL和标签或分支 s.source = { :path => '.' } + + # 包含库的主要源代码文件 s.source_files = 'Classes/**/*' + # s.public_header_files和s.private_header_files:分别指定公共和私有头文件。 + s.public_header_files = 'Classes/**/*.h' + + # 库的资源文件,如图片、故事板等 + # s.resources = "" + + + # s.pod_target_xcconfig和s.xcconfig:Xcode项目的配置信息。 + # 库依赖的其他CocoaPods库。 s.dependency 'Flutter' - s.platform = :ios, '12.0' + # 依赖版本: https://github.com/CocoaPods/Specs/tree/master/Specs/a/a/a/GDTMobSDK + s.dependency 'GDTMobSDK','~> 4.15.10' + + # s.frameworks和s.libraries:库依赖的系统框架和库。 + s.static_framework = true + + # 库支持的最低iOS版本 + # s.watchos.deployment_target、s.tvos.deployment_target等:支持的其他平台和版本。 + # 广点通的 SDK 最低支持 9.0 所以,这里设置 9.0 + s.ios.deployment_target = '9.0' + # Pod 支持的平台和版本。例如:s.platform = :ios, '8.0' 表示这个 Pod 支持 iOS 8.0 及更高版本。 + # s.platform = :ios, '9.0' + + # s.prefix_header_contents:前缀头文件的内容。 + # s.ios.exclude_files、s.osx.exclude_files等:排除的文件和平台。 + # 通过这些参数,开发者可以详细描述自己的库,确保其他开发者能够正确地使用和集成该库‌ + + # s.vendored_frameworks = "Frameworks/*.framework" # Flutter.framework does not contain a i386 slice. s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } - s.swift_version = '5.0' + + # s.swift_version = '5.0' end