├── .gitignore ├── .metadata ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── lib │ └── open_ad_sdk_6.0.1.4.aar ├── settings.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── kotlin │ └── net │ │ └── niuxiaoer │ │ └── flutter_gromore │ │ ├── FlutterGromorePlugin.kt │ │ ├── InitGromore.kt │ │ ├── PluginDelegate.kt │ │ ├── constants │ │ └── FlutterGromoreConstants.kt │ │ ├── event │ │ ├── AdEvent.kt │ │ └── AdEventHandler.kt │ │ ├── factory │ │ ├── FlutterGromoreBannerFactory.kt │ │ ├── FlutterGromoreFeedFactory.kt │ │ └── FlutterGromoreSplashFactory.kt │ │ ├── manager │ │ ├── FlutterGromoreFeedCache.kt │ │ ├── FlutterGromoreFeedManager.kt │ │ ├── FlutterGromoreInterstitialCache.kt │ │ ├── FlutterGromoreInterstitialManager.kt │ │ ├── FlutterGromoreRewardCache.kt │ │ └── FlutterGromoreRewardManager.kt │ │ ├── utils │ │ └── Utils.kt │ │ └── view │ │ ├── FlutterGromoreBanner.kt │ │ ├── FlutterGromoreBase.kt │ │ ├── FlutterGromoreFeed.kt │ │ ├── FlutterGromoreInterstitial.kt │ │ ├── FlutterGromoreReward.kt │ │ ├── FlutterGromoreSplash.kt │ │ └── FlutterGromoreSplashView.kt │ └── res │ ├── layout │ └── splash.xml │ ├── mipmap │ └── launch_image.png │ ├── raw │ └── keep.xml │ ├── values │ └── themes.xml │ └── xml │ ├── bd_file_paths.xml │ ├── gdt_file_path.xml │ ├── mb_provider_paths.xml │ ├── pangle_file_paths.xml │ └── sigmob_provider_paths.xml ├── example ├── .gitignore ├── .metadata ├── README.md ├── analysis_options.yaml ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ ├── libs │ │ │ ├── Baidu_MobAds_SDK_v9.34.aar │ │ │ ├── GDTSDK.unionNormal.4.563.1433.aar │ │ │ ├── kssdk-ad-3.3.59.aar │ │ │ ├── mediation_baidu_adapter_9.34.0.aar │ │ │ ├── mediation_gdt_adapter_4.563.1433.0.aar │ │ │ ├── mediation_ks_adapter_3.3.59.0.aar │ │ │ └── open_ad_sdk_6.0.1.4.aar │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── net │ │ │ │ │ └── niuxiaoer │ │ │ │ │ └── flutter_gromore_example │ │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── launch_image.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── values-night │ │ │ │ └── styles.xml │ │ │ │ ├── values │ │ │ │ └── styles.xml │ │ │ │ └── xml │ │ │ │ └── network_config.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── ios │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Podfile │ ├── Podfile.lock │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── WorkspaceSettings.xcsettings │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ ├── Contents.json │ │ ├── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ │ └── launch_image.imageset │ │ │ ├── Contents.json │ │ │ └── launch_image.png │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ ├── Runner-Bridging-Header.h │ │ └── zh-Hans.lproj │ │ ├── LaunchScreen.strings │ │ └── Main.strings ├── lib │ ├── config │ │ └── config.dart │ ├── main.dart │ ├── pages │ │ ├── banner_demo.dart │ │ ├── custom_splash.dart │ │ └── feed_demo.dart │ ├── utils │ │ └── ad_utils.dart │ └── widgets │ │ ├── banner_view.dart │ │ └── feed_view.dart ├── pubspec.lock ├── pubspec.yaml └── test │ └── widget_test.dart ├── flutter_gromore.iml ├── ios ├── .gitignore ├── Assets │ └── .gitkeep ├── Classes │ ├── FlutterGromorePlugin.h │ ├── FlutterGromorePlugin.m │ ├── SwiftFlutterGromorePlugin.swift │ ├── constants │ │ └── FlutterGromoreConstants.swift │ ├── event │ │ ├── AdEvent.swift │ │ └── AdEventHandler.swift │ ├── factory │ │ ├── FlutterGromoreBannerFactory.swift │ │ └── FlutterGromoreFeedFactory.swift │ ├── manager │ │ ├── FlutterGromoreFeedCache.swift │ │ ├── FlutterGromoreFeedManager.swift │ │ ├── FlutterGromoreInterstitialCache.swift │ │ ├── FlutterGromoreInterstitialManager.swift │ │ ├── FlutterGromoreRewardCache.swift │ │ └── FlutterGromoreRewardManager.swift │ ├── utils │ │ ├── GCDTool.swift │ │ └── Utils.swift │ └── view │ │ ├── FlutterGromoreBanner.swift │ │ ├── FlutterGromoreBase.swift │ │ ├── FlutterGromoreFeed.swift │ │ ├── FlutterGromoreIntercptPenetrateView.swift │ │ ├── FlutterGromoreInterstitial.swift │ │ ├── FlutterGromoreReward.swift │ │ └── FlutterGromoreSplash.swift └── flutter_gromore.podspec ├── lib ├── callback │ ├── gromore_banner_callback.dart │ ├── gromore_base_callback.dart │ ├── gromore_feed_callback.dart │ ├── gromore_interstitial_callback.dart │ ├── gromore_method_channel_handler.dart │ ├── gromore_reward_callback.dart │ └── gromore_splash_callback.dart ├── config │ ├── gromore_banner_config.dart │ ├── gromore_base_config.dart │ ├── gromore_feed_config.dart │ ├── gromore_interstitial_config.dart │ ├── gromore_reward_config.dart │ └── gromore_splash_config.dart ├── constants │ └── gromore_constans.dart ├── flutter_gromore.dart ├── types.dart ├── utils │ └── gromore_ad_size.dart └── view │ ├── gromore_banner_view.dart │ ├── gromore_feed_view.dart │ └── gromore_splash_view.dart ├── pubspec.lock ├── pubspec.yaml ├── screenshots ├── group.jpg ├── ios-frameworks.png ├── pangle-xcode.png └── qrcode.jpg ├── test └── flutter_gromore_test.dart └── v1.x_README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | build/ 8 | 9 | .idea/ -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 4cc385b4b84ac2f816d939a49ea1f328c4e0b48e 8 | channel: stable 9 | 10 | project_type: plugin 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.0 2 | 3 | - 支持开屏广告 4 | - 支持插屏广告 5 | - 支持信息流广告 6 | 7 | ## 1.0.1 8 | 9 | - 修复iOS端穿山甲信息流广告点击穿透的问题 10 | 11 | ## 1.0.2 12 | 13 | - 修复Android端开屏广告事件通信调用顺序导致部分机型程序崩溃的问题 14 | 15 | ## 1.0.3 16 | 17 | - 修复FlutterGromoreSplash手动跳过时可能刚好触发了onAdDismiss事件,调用了两次finishActivity方法,导致App崩溃的问题 18 | 19 | ## 1.0.4 20 | 21 | - 修复context和activity类型混用 22 | 23 | ## 1.0.5 24 | 25 | - 更新Gromore版本到3.7.0.2 26 | 27 | ## 1.0.6 28 | 29 | - 添加本地缓存配置 30 | 31 | ## 1.0.7 32 | 33 | - 更新iOS端Gromore版本到4.8.0.7 34 | 35 | ## 1.0.8 36 | 37 | - 更新Android端Gromore版本到3.9.0.2 38 | - 针对不同信息流广告位ID进行缓存 39 | - 修复广点通广告高度问题 40 | 41 | ## 1.0.9 42 | 43 | - 修复开屏广告无响应问题 44 | 45 | ## 1.0.10 46 | 47 | - 修复iOS穿山甲信息流白屏问题 48 | - 优化了一些问题 49 | - 修复多次跳过开屏广告导致闪退的问题 50 | 51 | ## 1.0.11 52 | 53 | - appcompat版本修改为1.3.1 54 | 55 | ## 2.0.0 56 | 57 | - 升级Gromore版本(Android:v5.3.5.1,iOS:v5.1.7.0) 58 | - 接入聚合功能 59 | 60 | ## 2.0.1 61 | 62 | - 新增激励广告 63 | 64 | ## 2.0.2 65 | 66 | - 修复iOS信息流广告部分穿透以及点击穿透问题 67 | 68 | ## 2.0.3 69 | 70 | - 修复初始化多次回调导致崩溃的问题 71 | 72 | ## 2.0.4 73 | 74 | - 修改初始化SDK逻辑,增加返回值 75 | 76 | ## 2.0.5 77 | 78 | - 新增banner广告 79 | 80 | ## 2.0.6 81 | 82 | - 修复百度开屏偶现无法关闭的问题 83 | - 修复了一些报错 84 | 85 | ## 2.0.7 86 | 87 | - 在demo中集成快手广告 88 | - 针对快手的信息流广告高度兼容处理 89 | 90 | ## 2.0.8 91 | 92 | - 开屏广告增加自动关闭/跳过逻辑 93 | 94 | ## 2.0.9 95 | 96 | - iOS开屏广告自动关闭/跳过逻辑 97 | 98 | ## 2.0.10 99 | 100 | - 更新Gromore版本5.5.1.5 101 | 102 | ## 2.1.0 103 | 104 | - 更新Gromore版本6.0.1.4、增加对SurfaceView的支持。强烈建议升级! -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Stahsf 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | group 'net.niuxiaoer.flutter_gromore' 2 | version '1.0-SNAPSHOT' 3 | 4 | buildscript { 5 | ext.kotlin_version = '1.6.10' 6 | repositories { 7 | google() 8 | mavenCentral() 9 | //mintegral sdk依赖 引入mintegral sdk需要添加此maven 10 | maven { 11 | url "https://dl-maven-android.mintegral.com/repository/mbridge_android_sdk_support/" 12 | } 13 | // GroMore SDK 14 | maven { 15 | url 'https://artifact.bytedance.com/repository/pangle' 16 | } 17 | } 18 | 19 | dependencies { 20 | classpath 'com.android.tools.build:gradle:4.1.0' 21 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 22 | } 23 | } 24 | 25 | rootProject.allprojects { 26 | repositories { 27 | google() 28 | mavenCentral() 29 | //mintegral sdk依赖 引入mintegral sdk需要添加此maven 30 | maven { 31 | url "https://dl-maven-android.mintegral.com/repository/mbridge_android_sdk_support/" 32 | } 33 | // GroMore SDK 34 | maven { 35 | url 'https://artifact.bytedance.com/repository/pangle' 36 | } 37 | } 38 | } 39 | 40 | apply plugin: 'com.android.library' 41 | apply plugin: 'kotlin-android' 42 | 43 | android { 44 | compileSdkVersion 30 45 | 46 | compileOptions { 47 | sourceCompatibility JavaVersion.VERSION_1_8 48 | targetCompatibility JavaVersion.VERSION_1_8 49 | } 50 | 51 | kotlinOptions { 52 | jvmTarget = '1.8' 53 | } 54 | 55 | sourceSets { 56 | main.java.srcDirs += 'src/main/kotlin' 57 | } 58 | 59 | defaultConfig { 60 | minSdkVersion 16 61 | } 62 | } 63 | 64 | repositories { 65 | flatDir { 66 | dirs 'lib' 67 | } 68 | } 69 | 70 | dependencies { 71 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 72 | implementation "androidx.appcompat:appcompat:1.3.1" 73 | implementation "androidx.constraintlayout:constraintlayout:2.1.4" 74 | 75 | 76 | // 融合SDK 77 | implementation(name: 'open_ad_sdk_6.0.1.4', ext: 'aar') 78 | implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0' 79 | } 80 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-all.zip 6 | -------------------------------------------------------------------------------- /android/lib/open_ad_sdk_6.0.1.4.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/android/lib/open_ad_sdk_6.0.1.4.aar -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'flutter_gromore' 2 | include ':lib' -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 12 | 13 | 14 | 19 | 22 | 23 | 24 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /android/src/main/kotlin/net/niuxiaoer/flutter_gromore/FlutterGromorePlugin.kt: -------------------------------------------------------------------------------- 1 | package net.niuxiaoer.flutter_gromore 2 | 3 | import io.flutter.embedding.engine.plugins.FlutterPlugin 4 | import io.flutter.embedding.engine.plugins.activity.ActivityAware 5 | import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding 6 | import io.flutter.plugin.common.BinaryMessenger 7 | import io.flutter.plugin.common.EventChannel 8 | import io.flutter.plugin.common.MethodChannel 9 | import net.niuxiaoer.flutter_gromore.constants.FlutterGromoreConstants 10 | import net.niuxiaoer.flutter_gromore.event.AdEventHandler 11 | import net.niuxiaoer.flutter_gromore.factory.FlutterGromoreBannerFactory 12 | import net.niuxiaoer.flutter_gromore.factory.FlutterGromoreFeedFactory 13 | import net.niuxiaoer.flutter_gromore.factory.FlutterGromoreSplashFactory 14 | 15 | /** FlutterGromorePlugin */ 16 | class FlutterGromorePlugin : FlutterPlugin, ActivityAware { 17 | 18 | // 通道实例 19 | private lateinit var methodChannel: MethodChannel 20 | private lateinit var eventChannel: EventChannel 21 | 22 | // 代理 23 | private var pluginDelegate: PluginDelegate? = null 24 | private var adEventListener: AdEventHandler? = null 25 | 26 | private lateinit var flutterPluginBinding: FlutterPlugin.FlutterPluginBinding 27 | private lateinit var binaryMessenger: BinaryMessenger 28 | 29 | override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { 30 | this.flutterPluginBinding = flutterPluginBinding 31 | binaryMessenger = flutterPluginBinding.binaryMessenger 32 | 33 | methodChannel = MethodChannel(binaryMessenger, FlutterGromoreConstants.methodChannelName) 34 | eventChannel = EventChannel(binaryMessenger, FlutterGromoreConstants.eventChannelName) 35 | } 36 | 37 | override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { 38 | methodChannel.setMethodCallHandler(null) 39 | eventChannel.setStreamHandler(null) 40 | } 41 | 42 | override fun onAttachedToActivity(binding: ActivityPluginBinding) { 43 | adEventListener = adEventListener ?: AdEventHandler.getInstance() 44 | pluginDelegate = pluginDelegate ?: PluginDelegate( 45 | flutterPluginBinding.applicationContext, 46 | binding.activity, 47 | binaryMessenger 48 | ) 49 | 50 | methodChannel.setMethodCallHandler(pluginDelegate) 51 | eventChannel.setStreamHandler(adEventListener) 52 | 53 | // 注册PlatformView 54 | flutterPluginBinding 55 | .platformViewRegistry 56 | .registerViewFactory( 57 | FlutterGromoreConstants.feedViewTypeId, 58 | FlutterGromoreFeedFactory(binding.activity, binaryMessenger) 59 | ) 60 | 61 | flutterPluginBinding 62 | .platformViewRegistry 63 | .registerViewFactory( 64 | FlutterGromoreConstants.splashTypeId, 65 | FlutterGromoreSplashFactory(binding.activity, binaryMessenger) 66 | ) 67 | 68 | flutterPluginBinding 69 | .platformViewRegistry 70 | .registerViewFactory( 71 | FlutterGromoreConstants.bannerTypeId, 72 | FlutterGromoreBannerFactory(binding.activity, binaryMessenger) 73 | ) 74 | } 75 | 76 | override fun onDetachedFromActivityForConfigChanges() { 77 | onDetachedFromActivity() 78 | } 79 | 80 | override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { 81 | onAttachedToActivity(binding) 82 | } 83 | 84 | override fun onDetachedFromActivity() { 85 | pluginDelegate = null 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /android/src/main/kotlin/net/niuxiaoer/flutter_gromore/PluginDelegate.kt: -------------------------------------------------------------------------------- 1 | package net.niuxiaoer.flutter_gromore 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.content.Intent 6 | import android.util.Log 7 | import io.flutter.plugin.common.BinaryMessenger 8 | import io.flutter.plugin.common.MethodCall 9 | import io.flutter.plugin.common.MethodChannel 10 | import net.niuxiaoer.flutter_gromore.manager.* 11 | import net.niuxiaoer.flutter_gromore.utils.Utils 12 | import net.niuxiaoer.flutter_gromore.view.FlutterGromoreInterstitial 13 | import net.niuxiaoer.flutter_gromore.view.FlutterGromoreReward 14 | import net.niuxiaoer.flutter_gromore.view.FlutterGromoreSplash 15 | 16 | class PluginDelegate( 17 | private val context: Context, 18 | private val activity: Activity, 19 | private val binaryMessenger: BinaryMessenger 20 | ) : MethodChannel.MethodCallHandler { 21 | private val TAG: String = this::class.java.simpleName 22 | 23 | override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { 24 | val method: String = call.method 25 | val arguments = call.arguments as? Map 26 | 27 | Log.d(TAG, method) 28 | 29 | when (method) { 30 | // 同时请求:READ_PHONE_STATE, COARSE_LOCATION, FINE_LOCATION, WRITE_EXTERNAL_STORAGE权限 31 | "requestPermissionIfNecessary" -> { 32 | result.success(true) 33 | } 34 | // 初始化 35 | "initSDK" -> { 36 | InitGromore(context).initSDK(arguments, result) 37 | } 38 | // 开屏 39 | "showSplashAd" -> { 40 | showSplash(arguments) 41 | // 在开屏广告关闭后才会调用result.success 42 | Utils.splashResult = result 43 | } 44 | // 加载插屏广告 45 | "loadInterstitialAd" -> { 46 | require(arguments != null && arguments["adUnitId"] != null) 47 | FlutterGromoreInterstitialManager(arguments, activity, result) 48 | } 49 | // 展示插屏广告 50 | "showInterstitialAd" -> { 51 | require(arguments != null && arguments["interstitialId"] != null) 52 | FlutterGromoreInterstitial(activity, binaryMessenger, arguments, result) 53 | } 54 | // 移除插屏广告 55 | "removeInterstitialAd" -> { 56 | require(arguments != null && arguments["interstitialId"] != null) 57 | FlutterGromoreInterstitialCache.removeCacheInterstitialAd((arguments["interstitialId"] as String).toInt()) 58 | result.success(true) 59 | } 60 | // 加载信息流广告 61 | "loadFeedAd" -> { 62 | require(arguments != null && arguments["adUnitId"] != null) 63 | FlutterGromoreFeedManager(arguments, context, result) 64 | } 65 | // 移除信息流广告 66 | "removeFeedAd" -> { 67 | require(arguments != null && arguments["feedId"] != null) 68 | FlutterGromoreFeedCache.removeCacheFeedAd(arguments["feedId"] as String) 69 | result.success(true) 70 | } 71 | // 加载激励广告 72 | "loadRewardAd" -> { 73 | require(arguments != null && arguments["adUnitId"] != null) 74 | FlutterGromoreRewardManager(arguments, activity, result) 75 | } 76 | // 展示激励广告 77 | "showRewardAd" -> { 78 | require(arguments != null && arguments["rewardId"] != null) 79 | FlutterGromoreReward(activity, binaryMessenger, arguments, result) 80 | } 81 | 82 | else -> { 83 | Log.d(TAG, "unknown method $method") 84 | result.success(true) 85 | } 86 | } 87 | } 88 | 89 | // 开屏广告 90 | private fun showSplash(arguments: Map?) { 91 | 92 | require(arguments != null) 93 | 94 | val intent = Intent(context, FlutterGromoreSplash::class.java).apply { 95 | putExtra("id", arguments["id"] as? String) 96 | putExtra("adUnitId", arguments["adUnitId"] as? String) 97 | putExtra("logo", arguments["logo"] as? String) 98 | putExtra("muted", arguments["muted"] as? Boolean) 99 | putExtra("preload", arguments["preload"] as? Boolean) 100 | putExtra("volume", arguments["volume"] as? Float) 101 | putExtra("timeout", arguments["timeout"] as? Int) 102 | putExtra("useSurfaceView", arguments["useSurfaceView"] as? Boolean) 103 | } 104 | 105 | activity.apply { 106 | startActivity(intent) 107 | activity.overridePendingTransition(0, 0) 108 | } 109 | 110 | } 111 | 112 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/net/niuxiaoer/flutter_gromore/constants/FlutterGromoreConstants.kt: -------------------------------------------------------------------------------- 1 | package net.niuxiaoer.flutter_gromore.constants 2 | 3 | class FlutterGromoreConstants { 4 | companion object { 5 | // 事件名 6 | const val methodChannelName = "flutter_gromore" 7 | const val eventChannelName = "flutter_gromore_event" 8 | 9 | // viewTypeId 10 | const val feedViewTypeId = "flutter_gromore_feed" 11 | 12 | // 插屏 13 | const val interstitialTypeId = "flutter_gromore_interstitial" 14 | 15 | // 开屏 16 | const val splashTypeId = "flutter_gromore_splash" 17 | 18 | // 激励视频 19 | const val rewardTypeId = "flutter_gromore_reward" 20 | 21 | // banner广告 22 | const val bannerTypeId = "flutter_gromore_banner" 23 | } 24 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/net/niuxiaoer/flutter_gromore/event/AdEvent.kt: -------------------------------------------------------------------------------- 1 | package net.niuxiaoer.flutter_gromore.event 2 | 3 | class AdEvent(private val id: String, private val name: String) { 4 | 5 | fun toMap(): HashMap { 6 | return HashMap().apply { 7 | set("id", id) 8 | set("name", name) 9 | } 10 | } 11 | 12 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/net/niuxiaoer/flutter_gromore/event/AdEventHandler.kt: -------------------------------------------------------------------------------- 1 | package net.niuxiaoer.flutter_gromore.event 2 | 3 | import android.util.Log 4 | import io.flutter.plugin.common.EventChannel 5 | 6 | class AdEventHandler: EventChannel.StreamHandler { 7 | private val TAG: String = this::class.java.simpleName 8 | private var eventSink: EventChannel.EventSink? = null 9 | 10 | companion object { 11 | // 单例 12 | fun getInstance() = InstanceHelper.instance 13 | } 14 | 15 | object InstanceHelper { 16 | val instance = AdEventHandler() 17 | } 18 | 19 | fun sendEvent(adEvent: AdEvent) { 20 | eventSink?.success(adEvent.toMap()) 21 | } 22 | 23 | override fun onListen(arguments: Any?, events: EventChannel.EventSink?) { 24 | Log.d(TAG, "onListen") 25 | eventSink = events 26 | } 27 | 28 | override fun onCancel(arguments: Any?) { 29 | Log.d(TAG, "onCancel") 30 | eventSink = null 31 | } 32 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/net/niuxiaoer/flutter_gromore/factory/FlutterGromoreBannerFactory.kt: -------------------------------------------------------------------------------- 1 | package net.niuxiaoer.flutter_gromore.factory 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import io.flutter.plugin.common.BinaryMessenger 6 | import io.flutter.plugin.common.StandardMessageCodec 7 | import io.flutter.plugin.platform.PlatformView 8 | import io.flutter.plugin.platform.PlatformViewFactory 9 | import net.niuxiaoer.flutter_gromore.view.FlutterGromoreBanner 10 | 11 | class FlutterGromoreBannerFactory( 12 | private val activity: Activity, 13 | private val binaryMessenger: BinaryMessenger 14 | ) : PlatformViewFactory(StandardMessageCodec.INSTANCE) { 15 | override fun create(context: Context, viewId: Int, args: Any?): PlatformView { 16 | val creationParams = args as Map 17 | return FlutterGromoreBanner(context, activity, viewId, creationParams, binaryMessenger); 18 | } 19 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/net/niuxiaoer/flutter_gromore/factory/FlutterGromoreFeedFactory.kt: -------------------------------------------------------------------------------- 1 | package net.niuxiaoer.flutter_gromore.factory 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.util.Log 6 | import io.flutter.plugin.common.BinaryMessenger 7 | import io.flutter.plugin.common.StandardMessageCodec 8 | import io.flutter.plugin.platform.PlatformView 9 | import io.flutter.plugin.platform.PlatformViewFactory 10 | import net.niuxiaoer.flutter_gromore.view.FlutterGromoreFeed 11 | 12 | class FlutterGromoreFeedFactory( 13 | private val activity: Activity, 14 | private val binaryMessenger: BinaryMessenger 15 | ) : PlatformViewFactory(StandardMessageCodec.INSTANCE) { 16 | override fun create(context: Context, viewId: Int, args: Any?): PlatformView { 17 | val creationParams = args as Map 18 | return FlutterGromoreFeed(context, activity, viewId, creationParams, binaryMessenger); 19 | } 20 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/net/niuxiaoer/flutter_gromore/factory/FlutterGromoreSplashFactory.kt: -------------------------------------------------------------------------------- 1 | package net.niuxiaoer.flutter_gromore.factory 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import io.flutter.plugin.common.BinaryMessenger 6 | import io.flutter.plugin.common.StandardMessageCodec 7 | import io.flutter.plugin.platform.PlatformView 8 | import io.flutter.plugin.platform.PlatformViewFactory 9 | import net.niuxiaoer.flutter_gromore.view.FlutterGromoreSplashView 10 | 11 | class FlutterGromoreSplashFactory( 12 | private val activity: Activity, 13 | private val binaryMessenger: BinaryMessenger 14 | ) : 15 | PlatformViewFactory(StandardMessageCodec.INSTANCE) { 16 | override fun create(context: Context, viewId: Int, args: Any?): PlatformView { 17 | val creationParams = args as Map? 18 | return FlutterGromoreSplashView(context, activity, viewId, creationParams, binaryMessenger); 19 | } 20 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/net/niuxiaoer/flutter_gromore/manager/FlutterGromoreFeedCache.kt: -------------------------------------------------------------------------------- 1 | package net.niuxiaoer.flutter_gromore.manager 2 | 3 | import com.bytedance.sdk.openadsdk.TTFeedAd 4 | 5 | class FlutterGromoreFeedCache { 6 | companion object { 7 | /// 缓存信息流广告 8 | var cacheFeedAd: MutableMap = mutableMapOf() 9 | 10 | /// 添加缓存信息流广告 11 | fun addCacheFeedAd(id: String, ad: TTFeedAd) { 12 | cacheFeedAd[id] = ad 13 | } 14 | 15 | /// 获取缓存信息流广告 16 | fun getCacheFeedAd(id: String): TTFeedAd? { 17 | return cacheFeedAd[id] 18 | } 19 | 20 | /// 移除缓存信息流广告 21 | fun removeCacheFeedAd(id: String) { 22 | cacheFeedAd.remove(id) 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/net/niuxiaoer/flutter_gromore/manager/FlutterGromoreFeedManager.kt: -------------------------------------------------------------------------------- 1 | package net.niuxiaoer.flutter_gromore.manager 2 | 3 | import android.content.Context 4 | import com.bytedance.sdk.openadsdk.AdSlot 5 | import com.bytedance.sdk.openadsdk.TTAdNative 6 | import com.bytedance.sdk.openadsdk.TTAdSdk 7 | import com.bytedance.sdk.openadsdk.TTFeedAd 8 | import com.bytedance.sdk.openadsdk.mediation.ad.MediationAdSlot 9 | import io.flutter.plugin.common.MethodChannel 10 | import net.niuxiaoer.flutter_gromore.utils.Utils 11 | 12 | class FlutterGromoreFeedManager( 13 | private val params: Map, 14 | private val context: Context, 15 | private val result: MethodChannel.Result 16 | ) : 17 | TTAdNative.FeedAdListener { 18 | 19 | init { 20 | loadAd() 21 | } 22 | 23 | /// 加载信息流广告 24 | fun loadAd() { 25 | 26 | // 广告位id 27 | val adUnitId = params["adUnitId"] as String 28 | // 加载数量 29 | var count = params["count"] as? Int ?: 3 30 | // 默认宽度占满 31 | val width = params["width"] as? Int ?: Utils.getScreenWidthInPx(context) 32 | // 0为高度选择自适应参数 33 | val height = params["height"] as? Int ?: 0 34 | // 是否使用SurfaceView 35 | val useSurfaceView = params["useSurfaceView"] as? Boolean ?: true 36 | 37 | require(adUnitId.isNotEmpty()) 38 | require(count > 0) 39 | 40 | val adNativeLoader = TTAdSdk.getAdManager().createAdNative(context) 41 | 42 | val adslot = AdSlot.Builder() 43 | .setCodeId(adUnitId) 44 | .setImageAcceptedSize(width, Utils.dp2px(context, height.toFloat())) 45 | .setAdCount(count) 46 | .setMediationAdSlot(MediationAdSlot.Builder().setUseSurfaceView(useSurfaceView).build()) 47 | .build() 48 | 49 | adNativeLoader.loadFeedAd(adslot, this) 50 | } 51 | 52 | // 信息流广告加载失败 53 | override fun onError(p0: Int, p1: String?) { 54 | result.error(p0.toString(), p1, p1) 55 | } 56 | 57 | // 信息流广告加载成功 58 | override fun onFeedAdLoad(ad: MutableList?) { 59 | val feedIdList: MutableList = ArrayList() 60 | val adUnitId = params["adUnitId"] as String 61 | 62 | ad?.forEach { 63 | val id = "${adUnitId}_${it.hashCode()}" 64 | feedIdList.add(id) 65 | FlutterGromoreFeedCache.addCacheFeedAd(id, it) 66 | } 67 | 68 | result.success(feedIdList) 69 | } 70 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/net/niuxiaoer/flutter_gromore/manager/FlutterGromoreInterstitialCache.kt: -------------------------------------------------------------------------------- 1 | package net.niuxiaoer.flutter_gromore.manager 2 | 3 | import com.bytedance.sdk.openadsdk.TTFullScreenVideoAd 4 | 5 | 6 | class FlutterGromoreInterstitialCache { 7 | companion object { 8 | /// 缓存插屏广告 9 | private var cacheInterstitialAd: MutableMap = mutableMapOf() 10 | 11 | /// 添加缓存插屏广告 12 | fun addCacheInterstitialAd(id: Int, ad: TTFullScreenVideoAd) { 13 | cacheInterstitialAd[id] = ad 14 | } 15 | 16 | /// 获取缓存插屏广告 17 | fun getCacheInterstitialAd(id: Int): TTFullScreenVideoAd? { 18 | return cacheInterstitialAd[id] 19 | } 20 | 21 | /// 移除缓存插屏广告 22 | fun removeCacheInterstitialAd(id: Int) { 23 | cacheInterstitialAd.remove(id) 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/net/niuxiaoer/flutter_gromore/manager/FlutterGromoreInterstitialManager.kt: -------------------------------------------------------------------------------- 1 | package net.niuxiaoer.flutter_gromore.manager 2 | 3 | import android.app.Activity 4 | import android.util.Log 5 | import com.bytedance.sdk.openadsdk.* 6 | import com.bytedance.sdk.openadsdk.mediation.ad.MediationAdSlot 7 | import io.flutter.plugin.common.MethodChannel 8 | 9 | class FlutterGromoreInterstitialManager( 10 | private val params: Map, 11 | private val activity: Activity, 12 | private val result: MethodChannel.Result 13 | ) : TTAdNative.FullScreenVideoAdListener { 14 | 15 | init { 16 | loadAd() 17 | } 18 | 19 | private fun loadAd() { 20 | val adUnitId = params["adUnitId"] as? String 21 | // 默认为竖 22 | val orientation = params["orientation"] as? Int ?: TTAdConstant.VERTICAL 23 | // 静音 24 | val muted = params["muted"] as? Boolean ?: true 25 | // 是否使用SurfaceView 26 | val useSurfaceView = params["useSurfaceView"] as? Boolean ?: true 27 | 28 | require(adUnitId != null && adUnitId.isNotEmpty()) 29 | 30 | val adNativeLoader = 31 | TTAdSdk.getAdManager().createAdNative(activity) 32 | val adslot = AdSlot.Builder() 33 | .setCodeId(adUnitId) // 广告位id 34 | .setAdCount(1) // 请求的广告数 35 | .setOrientation(orientation) 36 | .setMediationAdSlot( 37 | MediationAdSlot.Builder() 38 | .setMuted(muted) 39 | .setUseSurfaceView(useSurfaceView) 40 | .build() 41 | ) // 聚合广告请求配置 42 | .build() 43 | 44 | adNativeLoader.loadFullScreenVideoAd(adslot, this) 45 | } 46 | 47 | override fun onError(p0: Int, p1: String?) { 48 | Log.d("InterstitialManager", "onInterstitialLoadFail - $p0 - $p1") 49 | result.error(p0.toString(), p1, p1) 50 | } 51 | 52 | override fun onFullScreenVideoAdLoad(ad: TTFullScreenVideoAd?) { 53 | ad?.let { 54 | FlutterGromoreInterstitialCache.addCacheInterstitialAd(ad.hashCode(), it) 55 | result.success(ad.hashCode().toString()) 56 | } 57 | } 58 | 59 | override fun onFullScreenVideoCached() { 60 | } 61 | 62 | override fun onFullScreenVideoCached(p0: TTFullScreenVideoAd?) { 63 | } 64 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/net/niuxiaoer/flutter_gromore/manager/FlutterGromoreRewardCache.kt: -------------------------------------------------------------------------------- 1 | package net.niuxiaoer.flutter_gromore.manager 2 | 3 | import com.bytedance.sdk.openadsdk.TTRewardVideoAd 4 | 5 | class FlutterGromoreRewardCache { 6 | companion object { 7 | /// 缓存插屏广告 8 | private var cacheAd: MutableMap = mutableMapOf() 9 | 10 | /// 添加缓存插屏广告 11 | fun addCacheAd(id: Int, ad: TTRewardVideoAd) { 12 | cacheAd[id] = ad 13 | } 14 | 15 | /// 获取缓存插屏广告 16 | fun getCacheAd(id: Int): TTRewardVideoAd? { 17 | return cacheAd[id] 18 | } 19 | 20 | /// 移除缓存插屏广告 21 | fun removeCacheAd(id: Int) { 22 | cacheAd.remove(id) 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/net/niuxiaoer/flutter_gromore/manager/FlutterGromoreRewardManager.kt: -------------------------------------------------------------------------------- 1 | package net.niuxiaoer.flutter_gromore.manager 2 | 3 | import android.app.Activity 4 | import android.util.Log 5 | import com.bytedance.sdk.openadsdk.AdSlot 6 | import com.bytedance.sdk.openadsdk.TTAdNative 7 | import com.bytedance.sdk.openadsdk.TTAdSdk 8 | import com.bytedance.sdk.openadsdk.TTRewardVideoAd 9 | import com.bytedance.sdk.openadsdk.mediation.ad.MediationAdSlot 10 | import io.flutter.plugin.common.MethodChannel 11 | 12 | class FlutterGromoreRewardManager( 13 | private val params: Map, 14 | private val activity: Activity, 15 | private val result: MethodChannel.Result 16 | ) : 17 | TTAdNative.RewardVideoAdListener { 18 | 19 | init { 20 | loadAd() 21 | } 22 | 23 | /// 加载激励广告 24 | private fun loadAd() { 25 | val adUnitId = params["adUnitId"] as? String 26 | // 是否静音,默认为true 27 | val muted = params["muted"] as? Boolean ?: true 28 | // 音量,默认为0 29 | val volume = params["volume"] as? Float ?: 0f 30 | // 播放方向。竖屏:1,横屏:2。默认竖屏 31 | val orientation = params["orientation"] as? Int ?: 1 32 | // 是否使用SurfaceView 33 | val useSurfaceView = params["useSurfaceView"] as? Boolean ?: true 34 | 35 | require(!adUnitId.isNullOrEmpty()) 36 | 37 | val adNativeLoader = TTAdSdk.getAdManager().createAdNative(activity) 38 | 39 | val adslot = AdSlot.Builder() 40 | .setCodeId(adUnitId) // 广告位id 41 | .setAdCount(1) // 请求的广告数 42 | .setOrientation(orientation) 43 | .setMediationAdSlot( 44 | MediationAdSlot.Builder() 45 | .setMuted(muted) 46 | .setVolume(volume) 47 | .setUseSurfaceView(useSurfaceView) 48 | .build() 49 | ) // 聚合广告请求配置 50 | .build() 51 | 52 | adNativeLoader.loadRewardVideoAd(adslot, this) 53 | } 54 | 55 | override fun onError(p0: Int, p1: String?) { 56 | result.error(p0.toString(), p1, p0.toString()) 57 | } 58 | 59 | override fun onRewardVideoAdLoad(p0: TTRewardVideoAd?) { 60 | 61 | } 62 | 63 | override fun onRewardVideoCached() { 64 | 65 | } 66 | 67 | // 官方建议在onRewardVideoCached回调后,展示广告,提升播放体验 68 | override fun onRewardVideoCached(ad: TTRewardVideoAd?) { 69 | ad?.let { 70 | FlutterGromoreRewardCache.addCacheAd(ad.hashCode(), it) 71 | result.success(ad.hashCode().toString()) 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/net/niuxiaoer/flutter_gromore/utils/Utils.kt: -------------------------------------------------------------------------------- 1 | package net.niuxiaoer.flutter_gromore.utils 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.graphics.Color 6 | import android.os.Build 7 | import android.view.View 8 | import android.view.WindowManager 9 | import io.flutter.plugin.common.MethodChannel 10 | 11 | 12 | class Utils { 13 | companion object { 14 | // 开屏广告result,在开屏广告关闭后返回给dart端 15 | var splashResult: MethodChannel.Result? = null 16 | 17 | // 获取屏幕宽度 18 | fun getScreenWidthInPx(context: Context): Int { 19 | val dm = context.applicationContext.resources.displayMetrics 20 | return dm.widthPixels 21 | } 22 | 23 | // 获取屏幕高度 24 | fun getScreenHeightInPx(context: Context): Int { 25 | val dm = context.applicationContext.resources.displayMetrics 26 | return dm.heightPixels 27 | } 28 | 29 | // 屏幕密度 30 | fun getDensity(context: Context): Float { 31 | return context.resources.displayMetrics.density 32 | } 33 | 34 | // 状态栏透明 35 | fun setTranslucent(activity: Activity) { 36 | val window = activity.window 37 | /// 设置透明状态栏 38 | if (window != null) { 39 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 40 | window.statusBarColor = Color.TRANSPARENT 41 | } else { 42 | window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) 43 | } 44 | } 45 | } 46 | 47 | /* 隐藏虚拟按键 */ 48 | fun hideBottomUIMenu(activity: Activity) { 49 | //隐藏虚拟按键,并且全屏 50 | if (Build.VERSION.SDK_INT <= 11 && Build.VERSION.SDK_INT < 19) { 51 | // lower api 52 | activity.window.decorView.systemUiVisibility = View.GONE 53 | } else if (Build.VERSION.SDK_INT > 19) { 54 | // for new api versions. 55 | val decorView: View = activity.window.decorView 56 | val uiOptions = (View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 57 | or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_FULLSCREEN) 58 | decorView.systemUiVisibility = uiOptions 59 | } 60 | } 61 | 62 | fun dp2px(context: Context, dp: Float): Int { 63 | val scale = context.resources.displayMetrics.density 64 | return (dp * scale + 0.5f).toInt() 65 | } 66 | 67 | } 68 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/net/niuxiaoer/flutter_gromore/view/FlutterGromoreBase.kt: -------------------------------------------------------------------------------- 1 | package net.niuxiaoer.flutter_gromore.view 2 | 3 | import io.flutter.plugin.common.BinaryMessenger 4 | import io.flutter.plugin.common.MethodChannel 5 | 6 | /** 7 | * 广告基类 8 | * 必须实现 initAd 9 | * postMessage 发送事件 10 | */ 11 | abstract class FlutterGromoreBase(messenger: BinaryMessenger, channelName: String) { 12 | 13 | private val methodChannel = MethodChannel(messenger, channelName) 14 | 15 | // 初始化广告 16 | abstract fun initAd() 17 | 18 | // 发送事件消息 19 | protected fun postMessage(method: String, arguments: Map? = null) { 20 | methodChannel.invokeMethod(method, arguments) 21 | } 22 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/net/niuxiaoer/flutter_gromore/view/FlutterGromoreFeed.kt: -------------------------------------------------------------------------------- 1 | package net.niuxiaoer.flutter_gromore.view 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.graphics.Color 6 | import android.util.Log 7 | import android.view.View 8 | import android.view.ViewGroup 9 | import android.widget.FrameLayout 10 | import com.bytedance.sdk.openadsdk.TTAdDislike 11 | import com.bytedance.sdk.openadsdk.TTFeedAd 12 | import com.bytedance.sdk.openadsdk.mediation.ad.MediationExpressRenderListener 13 | import io.flutter.plugin.common.BinaryMessenger 14 | import io.flutter.plugin.platform.PlatformView 15 | import net.niuxiaoer.flutter_gromore.constants.FlutterGromoreConstants 16 | import net.niuxiaoer.flutter_gromore.manager.FlutterGromoreFeedCache 17 | import net.niuxiaoer.flutter_gromore.utils.Utils 18 | 19 | 20 | class FlutterGromoreFeed( 21 | private val context: Context, 22 | private val activity: Activity, 23 | viewId: Int, 24 | creationParams: Map, 25 | binaryMessenger: BinaryMessenger 26 | ) : 27 | FlutterGromoreBase(binaryMessenger, "${FlutterGromoreConstants.feedViewTypeId}/$viewId"), 28 | PlatformView, 29 | TTAdDislike.DislikeInteractionCallback, MediationExpressRenderListener { 30 | 31 | private val TAG: String = this::class.java.simpleName 32 | 33 | // 信息流广告容器 34 | private var container: FrameLayout = FrameLayout(context) 35 | 36 | // 广告model 37 | private var mGMNativeAd: TTFeedAd? = null 38 | 39 | private var layoutParams: FrameLayout.LayoutParams = FrameLayout.LayoutParams( 40 | ViewGroup.LayoutParams.WRAP_CONTENT, 41 | ViewGroup.LayoutParams.WRAP_CONTENT 42 | ) 43 | 44 | private val cachedAdId: String 45 | 46 | init { 47 | container.layoutParams = layoutParams 48 | cachedAdId = creationParams["feedId"] as String 49 | // 从缓存中取广告 50 | mGMNativeAd = 51 | FlutterGromoreFeedCache.getCacheFeedAd(cachedAdId) 52 | initAd() 53 | } 54 | 55 | private fun showAd() { 56 | 57 | mGMNativeAd?.takeIf { 58 | it.mediationManager.isReady 59 | }?.let { 60 | 61 | // 是否有不喜欢按钮 62 | if (it.mediationManager.hasDislike()) { 63 | it.setDislikeCallback(activity, this) 64 | } 65 | 66 | if (it.mediationManager.isExpress) { 67 | it.setExpressRenderListener(this) 68 | } 69 | 70 | it.render() 71 | } 72 | } 73 | 74 | private fun removeAdView() { 75 | container.removeAllViews() 76 | mGMNativeAd?.destroy() 77 | mGMNativeAd = null 78 | FlutterGromoreFeedCache.removeCacheFeedAd(cachedAdId) 79 | } 80 | 81 | override fun getView(): View { 82 | return container 83 | } 84 | 85 | override fun dispose() { 86 | removeAdView() 87 | } 88 | 89 | override fun onAdClick() { 90 | Log.d(TAG, "onAdClick") 91 | postMessage("onAdClick") 92 | } 93 | 94 | override fun onAdShow() { 95 | Log.d(TAG, "onAdShow") 96 | postMessage("onAdShow") 97 | } 98 | 99 | override fun onRenderFail(p0: View?, p1: String?, p2: Int) { 100 | Log.d(TAG, "onRenderFail - $p2 - $p1") 101 | postMessage("onRenderFail") 102 | } 103 | 104 | // 必须在onRenderSuccess进行广告展示,否则会导致广告无法展示 105 | override fun onRenderSuccess(p0: View?, width: Float, height: Float, isExpress: Boolean) { 106 | Log.d(TAG, "onRenderSuccess - $width - $height") 107 | 108 | val ad = mGMNativeAd?.adView 109 | ad?.let { view -> 110 | (view.parent as? ViewGroup)?.removeView(view) 111 | } 112 | 113 | ad?.apply { 114 | container.removeAllViews() 115 | container.setBackgroundColor(Color.WHITE) 116 | container.addView(ad) 117 | if (height > 0) { 118 | postMessage( 119 | "onRenderSuccess", 120 | mapOf("height" to height) 121 | ) 122 | return 123 | } 124 | } 125 | 126 | // 兼容height小于等于0的情况,如 快手广告 127 | ad?.apply { 128 | // 计算渲染后的高度 129 | measure(View.MeasureSpec.makeMeasureSpec(Utils.getScreenWidthInPx(context), View.MeasureSpec.UNSPECIFIED), 130 | View.MeasureSpec.makeMeasureSpec(Utils.getScreenHeightInPx(context), View.MeasureSpec.UNSPECIFIED)) 131 | Log.d(TAG, "measuredHeight - $measuredHeight") 132 | }?.takeIf { 133 | it.measuredHeight > 0 134 | }?.let { 135 | postMessage( 136 | "onRenderSuccess", 137 | mapOf("height" to it.measuredHeight / Utils.getDensity(context)) 138 | ) 139 | } 140 | 141 | } 142 | 143 | override fun onCancel() { 144 | Log.d(TAG, "dislike-onCancel") 145 | postMessage("onCancel") 146 | } 147 | 148 | override fun onShow() { 149 | Log.d(TAG, "dislike-onShow") 150 | postMessage("onShow") 151 | } 152 | 153 | // 用户选择不喜欢原因后,移除广告展示 154 | override fun onSelected(p0: Int, p1: String?, p2: Boolean) { 155 | Log.d(TAG, "dislike-onSelected") 156 | postMessage("onSelected") 157 | removeAdView() 158 | } 159 | 160 | override fun initAd() { 161 | showAd() 162 | } 163 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/net/niuxiaoer/flutter_gromore/view/FlutterGromoreInterstitial.kt: -------------------------------------------------------------------------------- 1 | package net.niuxiaoer.flutter_gromore.view 2 | 3 | import android.app.Activity 4 | import android.util.Log 5 | import com.bytedance.sdk.openadsdk.TTFullScreenVideoAd 6 | import io.flutter.plugin.common.BinaryMessenger 7 | import io.flutter.plugin.common.MethodChannel 8 | import net.niuxiaoer.flutter_gromore.constants.FlutterGromoreConstants 9 | import net.niuxiaoer.flutter_gromore.manager.FlutterGromoreInterstitialCache 10 | 11 | 12 | class FlutterGromoreInterstitial(private val activity: Activity, 13 | binaryMessenger: BinaryMessenger, 14 | creationParams: Map, 15 | private val result: MethodChannel.Result) : 16 | FlutterGromoreBase(binaryMessenger, "${FlutterGromoreConstants.interstitialTypeId}/${creationParams["interstitialId"]}"), TTFullScreenVideoAd.FullScreenVideoAdInteractionListener { 17 | 18 | private val TAG: String = this::class.java.simpleName 19 | 20 | private var mInterstitialAd: TTFullScreenVideoAd? = null 21 | private var interstitialId: Int = 0 22 | 23 | init { 24 | interstitialId = (creationParams["interstitialId"] as String).toInt() 25 | mInterstitialAd = FlutterGromoreInterstitialCache.getCacheInterstitialAd(interstitialId) 26 | initAd() 27 | } 28 | 29 | private fun showAd() { 30 | mInterstitialAd.takeIf { 31 | it != null && it.mediationManager.isReady 32 | }?.let { 33 | // 真正展示 34 | it.setFullScreenVideoAdInteractionListener(this) 35 | it.showFullScreenVideoAd(activity) 36 | } 37 | } 38 | 39 | // 初始化插屏广告 40 | override fun initAd() { 41 | showAd() 42 | } 43 | 44 | private fun destroyAd() { 45 | mInterstitialAd?.mediationManager?.destroy() 46 | mInterstitialAd = null 47 | 48 | FlutterGromoreInterstitialCache.removeCacheInterstitialAd(interstitialId) 49 | } 50 | 51 | // 广告展示 52 | override fun onAdShow() { 53 | Log.d(TAG, "onInterstitialShow") 54 | postMessage("onInterstitialShow") 55 | } 56 | 57 | // 广告被点击 58 | override fun onAdVideoBarClick() { 59 | Log.d(TAG, "onInterstitialAdClick") 60 | postMessage("onInterstitialAdClick") 61 | } 62 | 63 | // 关闭广告 64 | override fun onAdClose() { 65 | Log.d(TAG, "onInterstitialClosed") 66 | result.success(true) 67 | postMessage("onInterstitialClosed") 68 | destroyAd() 69 | } 70 | 71 | // 跳过视频 72 | override fun onSkippedVideo() { 73 | Log.d(TAG, "onSkippedVideo") 74 | } 75 | 76 | // 播放视频完成 77 | override fun onVideoComplete() { 78 | Log.d(TAG, "onVideoComplete") 79 | } 80 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/net/niuxiaoer/flutter_gromore/view/FlutterGromoreReward.kt: -------------------------------------------------------------------------------- 1 | package net.niuxiaoer.flutter_gromore.view 2 | 3 | import android.app.Activity 4 | import android.os.Bundle 5 | import android.util.Log 6 | import com.bytedance.sdk.openadsdk.TTRewardVideoAd 7 | import io.flutter.plugin.common.BinaryMessenger 8 | import io.flutter.plugin.common.MethodChannel 9 | import net.niuxiaoer.flutter_gromore.constants.FlutterGromoreConstants 10 | import net.niuxiaoer.flutter_gromore.manager.FlutterGromoreRewardCache 11 | 12 | class FlutterGromoreReward( 13 | private val activity: Activity, 14 | messenger: BinaryMessenger, 15 | creationParams: Map, 16 | private val result: MethodChannel.Result) : 17 | FlutterGromoreBase(messenger, "${FlutterGromoreConstants.rewardTypeId}/${creationParams["rewardId"]}"), 18 | TTRewardVideoAd.RewardAdInteractionListener { 19 | 20 | private val TAG: String = this::class.java.simpleName 21 | 22 | private var mttRewardAd: TTRewardVideoAd? = null 23 | private var rewardId: Int = 0 24 | 25 | init { 26 | rewardId = (creationParams["rewardId"] as String).toInt() 27 | mttRewardAd = FlutterGromoreRewardCache.getCacheAd(rewardId) 28 | 29 | initAd() 30 | } 31 | 32 | override fun initAd() { 33 | mttRewardAd?.takeIf { 34 | it.mediationManager.isReady 35 | }?.let { 36 | // 真正展示 37 | it.setRewardAdInteractionListener(this) 38 | it.showRewardVideoAd(activity) 39 | } 40 | } 41 | 42 | private fun destroyAd() { 43 | mttRewardAd?.mediationManager?.destroy() 44 | mttRewardAd = null 45 | 46 | FlutterGromoreRewardCache.removeCacheAd(rewardId) 47 | } 48 | 49 | override fun onAdShow() { 50 | Log.d(TAG, "onAdShow") 51 | postMessage("onAdShow") 52 | } 53 | 54 | // 广告的下载bar点击回调,非所有广告商的广告都会触发 55 | override fun onAdVideoBarClick() { 56 | Log.d(TAG, "onAdVideoBarClick") 57 | postMessage("onAdVideoBarClick") 58 | } 59 | 60 | // 广告关闭的回调 61 | override fun onAdClose() { 62 | Log.d(TAG, "onAdClose") 63 | postMessage("onAdClose") 64 | result.success(true) 65 | destroyAd() 66 | } 67 | 68 | // 视频播放完毕的回调,非所有广告商的广告都会触发 69 | override fun onVideoComplete() { 70 | Log.d(TAG, "onVideoComplete") 71 | postMessage("onVideoComplete") 72 | } 73 | 74 | // 视频播放失败的回调 75 | override fun onVideoError() { 76 | Log.d(TAG, "onVideoError") 77 | postMessage("onVideoError") 78 | result.error("0", "视频播放失败", "视频播放失败") 79 | } 80 | 81 | // 聚合不支持、激励视频播放完毕,验证是否有效发放奖励的回调 82 | override fun onRewardVerify(p0: Boolean, p1: Int, p2: String?, p3: Int, p4: String?) { 83 | Log.d(TAG, "onRewardVerify") 84 | postMessage("onRewardVerify", mapOf("verify" to p0)) 85 | } 86 | 87 | // 激励视频播放完毕,验证是否有效发放奖励的回调 88 | override fun onRewardArrived(p0: Boolean, p1: Int, p2: Bundle?) { 89 | Log.d(TAG, "onRewardVerify") 90 | postMessage("onRewardVerify", mapOf("verify" to p0)) 91 | } 92 | 93 | // 跳过广告 94 | override fun onSkippedVideo() { 95 | Log.d(TAG, "onSkippedVideo") 96 | postMessage("onSkippedVideo") 97 | } 98 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/net/niuxiaoer/flutter_gromore/view/FlutterGromoreSplashView.kt: -------------------------------------------------------------------------------- 1 | package net.niuxiaoer.flutter_gromore.view 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.util.Log 6 | import android.view.View 7 | import android.widget.FrameLayout 8 | import com.bytedance.sdk.openadsdk.AdSlot 9 | import com.bytedance.sdk.openadsdk.TTAdNative 10 | import com.bytedance.sdk.openadsdk.TTAdSdk 11 | import com.bytedance.sdk.openadsdk.TTSplashAd 12 | import com.bytedance.sdk.openadsdk.mediation.ad.MediationAdSlot 13 | import io.flutter.plugin.common.BinaryMessenger 14 | import io.flutter.plugin.platform.PlatformView 15 | import net.niuxiaoer.flutter_gromore.constants.FlutterGromoreConstants 16 | import net.niuxiaoer.flutter_gromore.utils.Utils 17 | 18 | 19 | class FlutterGromoreSplashView( 20 | private val context: Context, 21 | private val activity: Activity, 22 | viewId: Int, 23 | private val creationParams: Map?, 24 | binaryMessenger: BinaryMessenger 25 | ) : 26 | FlutterGromoreBase(binaryMessenger, "${FlutterGromoreConstants.splashTypeId}/$viewId"), 27 | PlatformView, TTAdNative.SplashAdListener, TTSplashAd.AdInteractionListener { 28 | 29 | private val TAG: String = this::class.java.simpleName 30 | 31 | // 开屏广告容器 32 | private var container: FrameLayout = FrameLayout(context) 33 | 34 | private var splashAd: TTSplashAd? = null 35 | 36 | init { 37 | initAd() 38 | } 39 | 40 | override fun initAd() { 41 | require(creationParams != null) 42 | 43 | val adUnitId = creationParams["adUnitId"] as String 44 | require(adUnitId.isNotEmpty()) 45 | 46 | val adNativeLoader = TTAdSdk.getAdManager().createAdNative(activity) 47 | 48 | // 注意开屏广告view:width >=70%屏幕宽;height >=50%屏幕高,否则会影响计费。 49 | // 开屏广告可支持的尺寸:图片尺寸传入与展示区域大小保持一致,避免素材变形 50 | val containerWidth = creationParams["width"] as? Int ?: Utils.getScreenWidthInPx(context) 51 | val containerHeight = creationParams["height"] as? Int ?: Utils.getScreenHeightInPx(context) 52 | val muted = creationParams["muted"] as? Boolean ?: false 53 | val preload = creationParams["preload"] as? Boolean ?: true 54 | val volume = creationParams["volume"] as? Float ?: 1f 55 | val isSplashShakeButton = creationParams["splashShakeButton"] as? Boolean ?: true 56 | val isBidNotify = creationParams["bidNotify"] as? Boolean ?: false 57 | 58 | container.layoutParams = FrameLayout.LayoutParams(containerWidth, containerHeight) 59 | 60 | val adSlot = AdSlot.Builder() 61 | .setImageAcceptedSize(containerWidth, containerHeight) 62 | .setMediationAdSlot(MediationAdSlot.Builder() 63 | .setSplashPreLoad(preload) 64 | .setMuted(muted) 65 | .setVolume(volume) 66 | .setSplashShakeButton(isSplashShakeButton) 67 | .setBidNotify(isBidNotify) 68 | .build()) 69 | .build() 70 | 71 | adNativeLoader.loadSplashAd(adSlot, this) 72 | } 73 | 74 | private fun finishSplash() { 75 | // 销毁 76 | splashAd?.mediationManager?.destroy() 77 | splashAd = null 78 | 79 | postMessage("onAdEnd") 80 | } 81 | 82 | override fun getView(): View { 83 | return container 84 | } 85 | 86 | override fun dispose() { 87 | finishSplash() 88 | } 89 | 90 | override fun onAdClicked(p0: View?, p1: Int) { 91 | Log.d(TAG, "onAdClicked") 92 | postMessage("onAdClicked") 93 | } 94 | 95 | override fun onAdShow(p0: View?, p1: Int) { 96 | Log.d(TAG, "onAdShow") 97 | postMessage("onAdShow") 98 | } 99 | 100 | override fun onAdSkip() { 101 | Log.d(TAG, "onAdSkip") 102 | 103 | finishSplash() 104 | postMessage("onAdSkip") 105 | } 106 | 107 | override fun onAdTimeOver() { 108 | Log.d(TAG, "onAdDismiss") 109 | 110 | finishSplash() 111 | postMessage("onAdDismiss") 112 | } 113 | 114 | override fun onError(p0: Int, p1: String?) { 115 | Log.d(TAG, "onSplashAdLoadFail") 116 | 117 | finishSplash() 118 | postMessage("onSplashAdLoadFail") 119 | } 120 | 121 | override fun onTimeout() { 122 | Log.d(TAG, "onAdLoadTimeout") 123 | 124 | finishSplash() 125 | postMessage("onAdLoadTimeout") 126 | } 127 | 128 | override fun onSplashAdLoad(ad: TTSplashAd?) { 129 | Log.d(TAG, "onSplashAdLoadSuccess") 130 | postMessage("onSplashAdLoadSuccess") 131 | 132 | ad?.let { 133 | splashAd = it 134 | it.setSplashInteractionListener(this) 135 | 136 | container.removeAllViews() 137 | it.splashView?.let { splashView -> 138 | container.addView(splashView) 139 | } 140 | } 141 | } 142 | 143 | } -------------------------------------------------------------------------------- /android/src/main/res/layout/splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 30 | -------------------------------------------------------------------------------- /android/src/main/res/mipmap/launch_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/android/src/main/res/mipmap/launch_image.png -------------------------------------------------------------------------------- /android/src/main/res/raw/keep.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /android/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 14 | -------------------------------------------------------------------------------- /android/src/main/res/xml/bd_file_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/src/main/res/xml/gdt_file_path.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | -------------------------------------------------------------------------------- /android/src/main/res/xml/mb_provider_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /android/src/main/res/xml/pangle_file_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/src/main/res/xml/sigmob_provider_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 4cc385b4b84ac2f816d939a49ea1f328c4e0b48e 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # flutter_gromore_example 2 | 3 | Demonstrates how to use the flutter_gromore plugin. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /example/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.dev/guides/language/analysis-options 30 | -------------------------------------------------------------------------------- /example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | def keystorePropertiesFile = rootProject.file("key.properties") 29 | def keystoreProperties = new Properties() 30 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) 31 | 32 | android { 33 | compileSdkVersion 33 34 | 35 | compileOptions { 36 | sourceCompatibility JavaVersion.VERSION_1_8 37 | targetCompatibility JavaVersion.VERSION_1_8 38 | } 39 | 40 | kotlinOptions { 41 | jvmTarget = '1.8' 42 | } 43 | 44 | sourceSets { 45 | main.java.srcDirs += 'src/main/kotlin' 46 | } 47 | 48 | defaultConfig { 49 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 50 | applicationId "com.android.niu_xiaoer" 51 | minSdkVersion 21 52 | targetSdkVersion 31 53 | versionCode flutterVersionCode.toInteger() 54 | versionName flutterVersionName 55 | multiDexEnabled true 56 | 57 | ndk { 58 | abiFilters 'armeabi', 'arm64-v8a', 'armeabi-v7a' 59 | } 60 | } 61 | 62 | signingConfigs { 63 | release { 64 | keyAlias keystoreProperties['keyAlias'] 65 | keyPassword keystoreProperties['keyPassword'] 66 | storeFile file(keystoreProperties['storeFile']) 67 | storePassword keystoreProperties['storePassword'] 68 | } 69 | } 70 | 71 | buildTypes { 72 | debug { 73 | signingConfig signingConfigs.release 74 | } 75 | 76 | release { 77 | signingConfig signingConfigs.release 78 | } 79 | } 80 | } 81 | 82 | flutter { 83 | source '../..' 84 | } 85 | 86 | repositories { 87 | flatDir { 88 | dirs 'libs' 89 | } 90 | maven { url 'https://artifact.bytedance.com/repository/AwemeOpenSDK' } 91 | } 92 | 93 | dependencies { 94 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 95 | 96 | implementation fileTree(include: ['*.jar'], dir: 'libs') 97 | // 广点通 SDK 98 | implementation (name: 'GDTSDK.unionNormal.4.563.1433', ext: 'aar') 99 | // 广点通 Adapter 100 | implementation(name: 'mediation_gdt_adapter_4.563.1433.0', ext: 'aar') 101 | // 百度SDK 102 | implementation(name: 'Baidu_MobAds_SDK_v9.34', ext: 'aar') 103 | // 百度 Adapter 104 | implementation(name: 'mediation_baidu_adapter_9.34.0', ext: 'aar') 105 | // 快手SDK 106 | implementation(name: 'kssdk-ad-3.3.59', ext: 'aar') 107 | // 快手 Adapter 108 | implementation(name: 'mediation_ks_adapter_3.3.59.0', ext: 'aar') 109 | } 110 | -------------------------------------------------------------------------------- /example/android/app/libs/Baidu_MobAds_SDK_v9.34.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/android/app/libs/Baidu_MobAds_SDK_v9.34.aar -------------------------------------------------------------------------------- /example/android/app/libs/GDTSDK.unionNormal.4.563.1433.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/android/app/libs/GDTSDK.unionNormal.4.563.1433.aar -------------------------------------------------------------------------------- /example/android/app/libs/kssdk-ad-3.3.59.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/android/app/libs/kssdk-ad-3.3.59.aar -------------------------------------------------------------------------------- /example/android/app/libs/mediation_baidu_adapter_9.34.0.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/android/app/libs/mediation_baidu_adapter_9.34.0.aar -------------------------------------------------------------------------------- /example/android/app/libs/mediation_gdt_adapter_4.563.1433.0.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/android/app/libs/mediation_gdt_adapter_4.563.1433.0.aar -------------------------------------------------------------------------------- /example/android/app/libs/mediation_ks_adapter_3.3.59.0.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/android/app/libs/mediation_ks_adapter_3.3.59.0.aar -------------------------------------------------------------------------------- /example/android/app/libs/open_ad_sdk_6.0.1.4.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/android/app/libs/open_ad_sdk_6.0.1.4.aar -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/net/niuxiaoer/flutter_gromore_example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package net.niuxiaoer.flutter_gromore_example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/launch_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/android/app/src/main/res/mipmap-hdpi/launch_image.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/xml/network_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.6.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-all.zip 7 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/ephemeral/ 22 | Flutter/app.flx 23 | Flutter/app.zip 24 | Flutter/flutter_assets/ 25 | Flutter/flutter_export_environment.sh 26 | ServiceDefinitions.json 27 | Runner/GeneratedPluginRegistrant.* 28 | 29 | # Exceptions to above rules. 30 | !default.mode1v3 31 | !default.mode2v3 32 | !default.pbxuser 33 | !default.perspectivev3 34 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 11.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '11.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | # SDK 版本需要查看 GroMore 提供 Adapter 的支持范围 35 | pod 'BaiduMobAdSDK', '5.34' 36 | pod 'CSJMBaiduAdapter', '5.34.0' 37 | pod 'GDTMobSDK', '4.14.63' 38 | pod 'CSJMGdtAdapter', '4.14.63.0' 39 | pod 'KSAdSDK', '3.3.61.0' 40 | pod 'CSJMKsAdapter', '3.3.61.0' 41 | 42 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 43 | end 44 | 45 | post_install do |installer| 46 | installer.pods_project.targets.each do |target| 47 | flutter_additional_ios_build_settings(target) 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /example/ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Ads-Fusion-CN-Beta (6.0.0.5): 3 | - Ads-Fusion-CN-Beta/BUAdSDK (= 6.0.0.5) 4 | - Ads-Fusion-CN-Beta/BUAdSDK (6.0.0.5) 5 | - Ads-Fusion-CN-Beta/CSJMediation (6.0.0.5): 6 | - Ads-Fusion-CN-Beta/BUAdSDK 7 | - BaiduMobAdSDK (5.34) 8 | - CSJMBaiduAdapter (5.34.0): 9 | - Ads-Fusion-CN-Beta/CSJMediation (>= 6.0.0.5) 10 | - CSJMGdtAdapter (4.14.63.0): 11 | - Ads-Fusion-CN-Beta/CSJMediation (>= 6.0.0.2) 12 | - CSJMKsAdapter (3.3.61.0.0): 13 | - Ads-Fusion-CN-Beta/CSJMediation (>= 6.0.0.2) 14 | - Flutter (1.0.0) 15 | - flutter_gromore (0.0.1): 16 | - Ads-Fusion-CN-Beta (= 6.0.0.5) 17 | - Flutter 18 | - flutter_gromore/BUAdSDK (= 0.0.1) 19 | - flutter_gromore/CSJMediation (= 0.0.1) 20 | - flutter_gromore/BUAdSDK (0.0.1): 21 | - Ads-Fusion-CN-Beta (= 6.0.0.5) 22 | - Ads-Fusion-CN-Beta/BUAdSDK (= 6.0.0.5) 23 | - Flutter 24 | - flutter_gromore/CSJMediation (0.0.1): 25 | - Ads-Fusion-CN-Beta (= 6.0.0.5) 26 | - Ads-Fusion-CN-Beta/CSJMediation (= 6.0.0.5) 27 | - Flutter 28 | - GDTMobSDK (4.14.63): 29 | - GDTMobSDK/GDTMobSDK (= 4.14.63) 30 | - GDTMobSDK/GDTMobSDK (4.14.63) 31 | - KSAdSDK (3.3.61) 32 | - permission_handler_apple (9.1.0): 33 | - Flutter 34 | 35 | DEPENDENCIES: 36 | - BaiduMobAdSDK (= 5.34) 37 | - CSJMBaiduAdapter (= 5.34.0) 38 | - CSJMGdtAdapter (= 4.14.63.0) 39 | - CSJMKsAdapter (= 3.3.61.0) 40 | - Flutter (from `Flutter`) 41 | - flutter_gromore (from `.symlinks/plugins/flutter_gromore/ios`) 42 | - GDTMobSDK (= 4.14.63) 43 | - KSAdSDK (= 3.3.61.0) 44 | - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) 45 | 46 | SPEC REPOS: 47 | trunk: 48 | - Ads-Fusion-CN-Beta 49 | - BaiduMobAdSDK 50 | - CSJMBaiduAdapter 51 | - CSJMGdtAdapter 52 | - CSJMKsAdapter 53 | - GDTMobSDK 54 | - KSAdSDK 55 | 56 | EXTERNAL SOURCES: 57 | Flutter: 58 | :path: Flutter 59 | flutter_gromore: 60 | :path: ".symlinks/plugins/flutter_gromore/ios" 61 | permission_handler_apple: 62 | :path: ".symlinks/plugins/permission_handler_apple/ios" 63 | 64 | SPEC CHECKSUMS: 65 | Ads-Fusion-CN-Beta: 151539e60342aa6096b7eef4358570abce27b216 66 | BaiduMobAdSDK: debcb4e54e00b461ae6b8f6fb8ee232d872cb42e 67 | CSJMBaiduAdapter: 966e2992ad47a3b589a979f295b2a2a2212b0ee2 68 | CSJMGdtAdapter: af4675b025885fe2a482b91baae2d27e56001510 69 | CSJMKsAdapter: 78a2ae637a45e3e2c1c307697da357d25ebd5339 70 | Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 71 | flutter_gromore: 43b8095366361a1a5136cdcfcb4708671500070e 72 | GDTMobSDK: 12270ef644af85e8032974b1a75df90593e96d1d 73 | KSAdSDK: 7754afd132df893c0c7a493fa878cbee7af6ff3c 74 | permission_handler_apple: 8f116445eff3c0e7c65ad60f5fef5490aa94b4e4 75 | 76 | PODFILE CHECKSUM: 8a034b11d7ec0262e9bf49ae0baa2a8be0784616 77 | 78 | COCOAPODS: 1.11.3 79 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/launch_image.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "launch_image.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 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/launch_image.imageset/launch_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/example/ios/Runner/Assets.xcassets/launch_image.imageset/launch_image.png -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 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 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 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 | 27 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | flutter_gromore_example 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | NSAppTransportSecurity 26 | 27 | NSAllowsArbitraryLoads 28 | 29 | 30 | NSUserTrackingUsageDescription 31 | 获取IDFA标记权限想您提供优质的个性化服务和内容 32 | UILaunchStoryboardName 33 | LaunchScreen 34 | UIMainStoryboardFile 35 | Main 36 | UISupportedInterfaceOrientations 37 | 38 | UIInterfaceOrientationPortrait 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UISupportedInterfaceOrientations~ipad 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationPortraitUpsideDown 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | UIViewControllerBasedStatusBarAppearance 50 | 51 | SKAdNetworkIdentifier 52 | 53 | x2jnk7ly8j.skadnetwork 54 | 238da6jt44.skadnetwork 55 | f7s53z58qe.skadnetwork 56 | 57 | 58 | CADisableMinimumFrameDurationOnPhone 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /example/ios/Runner/zh-Hans.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /example/ios/Runner/zh-Hans.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /example/lib/config/config.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | /// APP名称 4 | const APP_NAME = "牛小二招聘"; 5 | 6 | /// 是否是生产环境 7 | const IS_PRODUCTION = false; 8 | 9 | class GroMoreAdConfig { 10 | /// APP-ID 11 | static String get appId { 12 | if (Platform.isAndroid) { 13 | return '5320035'; 14 | } 15 | return '5410502'; 16 | } 17 | 18 | /// 开屏广告ID 19 | static String get splashId { 20 | if (Platform.isAndroid) { 21 | return '102357892'; 22 | } 23 | return '102392509'; 24 | } 25 | 26 | /// 信息流广告ID 27 | static String get feedId { 28 | if (Platform.isAndroid) { 29 | return '102361544'; 30 | } 31 | return '102391145'; 32 | } 33 | 34 | /// 插屏广告ID 35 | static String get interstitialId { 36 | if (Platform.isAndroid) { 37 | return '102360214'; 38 | } 39 | return '102390665'; 40 | } 41 | 42 | /// 激励视频广告ID 43 | static String get rewardId { 44 | if (Platform.isAndroid) { 45 | return '102363841'; 46 | } 47 | return '102754385'; 48 | } 49 | 50 | /// banner广告ID 51 | static String get bannerId { 52 | if (Platform.isAndroid) { 53 | return '102754191'; 54 | } 55 | return '102754949'; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /example/lib/pages/banner_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_gromore_example/widgets/banner_view.dart'; 3 | 4 | class BannerDemo extends StatefulWidget { 5 | const BannerDemo({Key? key}) : super(key: key); 6 | 7 | @override 8 | State createState() => _BannerDemoState(); 9 | } 10 | 11 | class _BannerDemoState extends State { 12 | List viewIds = []; 13 | 14 | @override 15 | void initState() { 16 | super.initState(); 17 | } 18 | 19 | handleBottomSheet() { 20 | showModalBottomSheet( 21 | context: context, 22 | builder: (_) => Material( 23 | child: SafeArea( 24 | top: false, 25 | child: Container( 26 | height: 200, 27 | width: double.infinity, 28 | color: Colors.red, 29 | child: Column( 30 | mainAxisAlignment: MainAxisAlignment.end, 31 | children: [ 32 | ElevatedButton( 33 | child: Text('确认'), 34 | onPressed: () { 35 | Navigator.of(context).pop(); 36 | }), 37 | ElevatedButton( 38 | child: Text('取消'), 39 | onPressed: () { 40 | Navigator.of(context).pop(); 41 | }) 42 | ], 43 | ), 44 | ), 45 | ), 46 | )); 47 | } 48 | 49 | @override 50 | Widget build(BuildContext context) { 51 | return Scaffold( 52 | appBar: AppBar( 53 | title: const Text("banner_demo"), 54 | ), 55 | body: Column( 56 | children: [ 57 | Expanded( 58 | child: ListView.builder( 59 | shrinkWrap: true, 60 | itemBuilder: (context, index) { 61 | if (index % 4 == 0) { 62 | return const BannerView(); 63 | } 64 | 65 | return Container( 66 | decoration: BoxDecoration( 67 | border: 68 | Border.all(color: const Color(0xffcccccc), width: 1)), 69 | alignment: Alignment.center, 70 | height: 200, 71 | child: Text(index.toString()), 72 | ); 73 | }, 74 | )), 75 | GestureDetector( 76 | onTap: handleBottomSheet, 77 | child: Container( 78 | color: Colors.blue, 79 | height: 50, 80 | child: const Center( 81 | child: Text("唤起bottomSheet"), 82 | ), 83 | ), 84 | ) 85 | ], 86 | ), 87 | ); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /example/lib/pages/custom_splash.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_gromore/callback/gromore_splash_callback.dart'; 3 | import 'package:flutter_gromore/config/gromore_splash_config.dart'; 4 | import 'package:flutter_gromore/view/gromore_splash_view.dart'; 5 | import 'package:flutter_gromore_example/config/config.dart'; 6 | 7 | class CustomSplash extends StatefulWidget { 8 | const CustomSplash({Key? key}) : super(key: key); 9 | 10 | @override 11 | State createState() => _CustomSplashState(); 12 | } 13 | 14 | class _CustomSplashState extends State { 15 | @override 16 | Widget build(BuildContext context) { 17 | double height = MediaQuery.of(context).size.height; 18 | 19 | return Scaffold( 20 | appBar: AppBar( 21 | title: const Text("自定义布局的开屏广告"), 22 | ), 23 | body: Column( 24 | children: [ 25 | Expanded( 26 | child: GromoreSplashView( 27 | creationParams: GromoreSplashConfig( 28 | adUnitId: GroMoreAdConfig.splashId, height: height - 80), 29 | callback: GromoreSplashCallback(onAdEnd: () { 30 | Navigator.pop(context); 31 | }), 32 | ), 33 | ), 34 | const SizedBox( 35 | height: 80, 36 | child: Center(child: Text("牛小二招聘")), 37 | ) 38 | ], 39 | ), 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /example/lib/pages/feed_demo.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_gromore_example/widgets/feed_view.dart'; 5 | 6 | class FeedDemo extends StatefulWidget { 7 | const FeedDemo({Key? key}) : super(key: key); 8 | 9 | @override 10 | State createState() => _FeedDemoState(); 11 | } 12 | 13 | class _FeedDemoState extends State { 14 | List viewIds = []; 15 | 16 | @override 17 | void initState() { 18 | super.initState(); 19 | } 20 | 21 | handleBottomSheet() { 22 | showModalBottomSheet( 23 | context: context, 24 | builder: (_) => Material( 25 | child: SafeArea( 26 | top: false, 27 | child: Container( 28 | height: 200, 29 | width: double.infinity, 30 | color: Colors.red, 31 | child: Column( 32 | mainAxisAlignment: MainAxisAlignment.end, 33 | children: [ 34 | ElevatedButton( 35 | child: Text('确认'), 36 | onPressed: () { 37 | Navigator.of(context).pop(); 38 | }), 39 | ElevatedButton( 40 | child: Text('取消'), 41 | onPressed: () { 42 | Navigator.of(context).pop(); 43 | }) 44 | ], 45 | ), 46 | ), 47 | ), 48 | )); 49 | } 50 | 51 | @override 52 | Widget build(BuildContext context) { 53 | return Scaffold( 54 | appBar: AppBar( 55 | title: const Text("feed_demo"), 56 | ), 57 | body: Column( 58 | children: [ 59 | Expanded( 60 | child: ListView.builder( 61 | shrinkWrap: true, 62 | itemBuilder: (context, index) { 63 | if (index % 4 == 0) { 64 | return const FeedView(); 65 | } 66 | 67 | return Container( 68 | decoration: BoxDecoration( 69 | border: 70 | Border.all(color: const Color(0xffcccccc), width: 1)), 71 | alignment: Alignment.center, 72 | height: 200, 73 | child: Text(index.toString()), 74 | ); 75 | }, 76 | )), 77 | GestureDetector( 78 | onTap: handleBottomSheet, 79 | child: Container( 80 | color: Colors.blue, 81 | height: 50, 82 | child: const Center( 83 | child: Text("唤起bottomSheet"), 84 | ), 85 | ), 86 | ) 87 | ], 88 | ), 89 | ); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /example/lib/utils/ad_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_gromore/config/gromore_banner_config.dart'; 2 | import 'package:flutter_gromore/config/gromore_feed_config.dart'; 3 | import 'package:flutter_gromore/flutter_gromore.dart'; 4 | import 'package:flutter_gromore_example/config/config.dart'; 5 | 6 | /// 广告工具类 7 | class AdUtils { 8 | static List feedAdIdList = []; 9 | static List bannerAdIdList = []; 10 | 11 | /// 获取信息流广告id 12 | static Future getFeedAdId() async { 13 | if (feedAdIdList.isNotEmpty) { 14 | return feedAdIdList.removeLast(); 15 | } 16 | 17 | // 加载信息流广告 18 | List idList = await FlutterGromore.loadFeedAd( 19 | GromoreFeedConfig(adUnitId: GroMoreAdConfig.feedId)); 20 | 21 | if (idList.isNotEmpty) { 22 | String id = idList.removeLast(); 23 | feedAdIdList.addAll(idList); 24 | return id; 25 | } 26 | 27 | return null; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /example/lib/widgets/banner_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_gromore/callback/gromore_banner_callback.dart'; 3 | import 'package:flutter_gromore/view/gromore_banner_view.dart'; 4 | import 'package:flutter_gromore_example/config/config.dart'; 5 | import 'package:flutter_gromore_example/utils/ad_utils.dart'; 6 | 7 | class BannerView extends StatefulWidget { 8 | const BannerView({Key? key}) : super(key: key); 9 | 10 | @override 11 | State createState() => _BannerViewState(); 12 | } 13 | 14 | class _BannerViewState extends State 15 | with AutomaticKeepAliveClientMixin { 16 | double _height = 0.1; 17 | final double _bannerHeight = 75; 18 | bool _show = true; 19 | 20 | @override 21 | void initState() { 22 | super.initState(); 23 | } 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | super.build(context); 28 | return _show 29 | ? SizedBox( 30 | height: _height, 31 | child: GromoreBannerView( 32 | creationParams: { 33 | "adUnitId": GroMoreAdConfig.bannerId, 34 | "height": _bannerHeight, 35 | "useSurfaceView": true, 36 | }, 37 | callback: GromoreBannerCallback(onRenderSuccess: () { 38 | print("GromoreBannerView | onRenderSuccess"); 39 | setState(() { 40 | _height = _bannerHeight; 41 | }); 42 | }, onSelected: () { 43 | setState(() { 44 | _show = false; 45 | }); 46 | }, onLoadError: () { 47 | setState(() { 48 | _show = false; 49 | }); 50 | }, onAdTerminate: () { 51 | setState(() { 52 | _show = false; 53 | }); 54 | })), 55 | ) 56 | : const SizedBox(); 57 | } 58 | 59 | @override 60 | bool get wantKeepAlive => true; 61 | } 62 | -------------------------------------------------------------------------------- /example/lib/widgets/feed_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_gromore/callback/gromore_feed_callback.dart'; 3 | import 'package:flutter_gromore/flutter_gromore.dart'; 4 | import 'package:flutter_gromore/view/gromore_feed_view.dart'; 5 | import 'package:flutter_gromore_example/utils/ad_utils.dart'; 6 | 7 | class FeedView extends StatefulWidget { 8 | const FeedView({Key? key}) : super(key: key); 9 | 10 | @override 11 | State createState() => _FeedViewState(); 12 | } 13 | 14 | class _FeedViewState extends State 15 | with AutomaticKeepAliveClientMixin { 16 | double _height = 0.1; 17 | bool _show = false; 18 | String? _feedAdId; 19 | 20 | @override 21 | void initState() { 22 | loadFeedAd(); 23 | super.initState(); 24 | } 25 | 26 | @override 27 | void dispose() { 28 | // 不需要手动移除,销毁时插件内部会处理 29 | // if (_feedAdId != null) { 30 | // FlutterGromore.removeFeedAd(_feedAdId!); 31 | // } 32 | super.dispose(); 33 | } 34 | 35 | loadFeedAd() async { 36 | String? feedAdId = await AdUtils.getFeedAdId(); 37 | print("loadFeedAd $feedAdId"); 38 | if (feedAdId != null && feedAdId.isNotEmpty) { 39 | setState(() { 40 | _feedAdId = feedAdId; 41 | _show = true; 42 | }); 43 | } 44 | } 45 | 46 | @override 47 | Widget build(BuildContext context) { 48 | super.build(context); 49 | return _show 50 | ? SizedBox( 51 | height: _height, 52 | child: GromoreFeedView( 53 | creationParams: {"feedId": _feedAdId!}, 54 | callback: GromoreFeedCallback(onRenderSuccess: (double height) { 55 | print("GromoreFeedView | onRenderSuccess | $height"); 56 | setState(() { 57 | _height = height; 58 | }); 59 | }, onSelected: () { 60 | setState(() { 61 | _show = false; 62 | }); 63 | }, onAdTerminate: () { 64 | setState(() { 65 | _show = false; 66 | }); 67 | })), 68 | ) 69 | : const SizedBox(); 70 | } 71 | 72 | @override 73 | bool get wantKeepAlive => true; 74 | } 75 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.flutter-io.cn" 9 | source: hosted 10 | version: "2.9.0" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.flutter-io.cn" 16 | source: hosted 17 | version: "2.1.0" 18 | characters: 19 | dependency: transitive 20 | description: 21 | name: characters 22 | url: "https://pub.flutter-io.cn" 23 | source: hosted 24 | version: "1.2.1" 25 | clock: 26 | dependency: transitive 27 | description: 28 | name: clock 29 | url: "https://pub.flutter-io.cn" 30 | source: hosted 31 | version: "1.1.1" 32 | collection: 33 | dependency: transitive 34 | description: 35 | name: collection 36 | url: "https://pub.flutter-io.cn" 37 | source: hosted 38 | version: "1.16.0" 39 | cupertino_icons: 40 | dependency: "direct main" 41 | description: 42 | name: cupertino_icons 43 | url: "https://pub.flutter-io.cn" 44 | source: hosted 45 | version: "1.0.4" 46 | fake_async: 47 | dependency: transitive 48 | description: 49 | name: fake_async 50 | url: "https://pub.flutter-io.cn" 51 | source: hosted 52 | version: "1.3.1" 53 | flutter: 54 | dependency: "direct main" 55 | description: flutter 56 | source: sdk 57 | version: "0.0.0" 58 | flutter_gromore: 59 | dependency: "direct main" 60 | description: 61 | path: ".." 62 | relative: true 63 | source: path 64 | version: "2.1.0" 65 | flutter_lints: 66 | dependency: "direct dev" 67 | description: 68 | name: flutter_lints 69 | url: "https://pub.flutter-io.cn" 70 | source: hosted 71 | version: "1.0.4" 72 | flutter_test: 73 | dependency: "direct dev" 74 | description: flutter 75 | source: sdk 76 | version: "0.0.0" 77 | lints: 78 | dependency: transitive 79 | description: 80 | name: lints 81 | url: "https://pub.flutter-io.cn" 82 | source: hosted 83 | version: "1.0.1" 84 | matcher: 85 | dependency: transitive 86 | description: 87 | name: matcher 88 | url: "https://pub.flutter-io.cn" 89 | source: hosted 90 | version: "0.12.12" 91 | material_color_utilities: 92 | dependency: transitive 93 | description: 94 | name: material_color_utilities 95 | url: "https://pub.flutter-io.cn" 96 | source: hosted 97 | version: "0.1.5" 98 | meta: 99 | dependency: transitive 100 | description: 101 | name: meta 102 | url: "https://pub.flutter-io.cn" 103 | source: hosted 104 | version: "1.8.0" 105 | path: 106 | dependency: transitive 107 | description: 108 | name: path 109 | url: "https://pub.flutter-io.cn" 110 | source: hosted 111 | version: "1.8.2" 112 | permission_handler: 113 | dependency: "direct main" 114 | description: 115 | name: permission_handler 116 | url: "https://pub.flutter-io.cn" 117 | source: hosted 118 | version: "10.0.2" 119 | permission_handler_android: 120 | dependency: transitive 121 | description: 122 | name: permission_handler_android 123 | url: "https://pub.flutter-io.cn" 124 | source: hosted 125 | version: "10.2.3" 126 | permission_handler_apple: 127 | dependency: transitive 128 | description: 129 | name: permission_handler_apple 130 | url: "https://pub.flutter-io.cn" 131 | source: hosted 132 | version: "9.1.0" 133 | permission_handler_platform_interface: 134 | dependency: transitive 135 | description: 136 | name: permission_handler_platform_interface 137 | url: "https://pub.flutter-io.cn" 138 | source: hosted 139 | version: "3.10.0" 140 | permission_handler_windows: 141 | dependency: transitive 142 | description: 143 | name: permission_handler_windows 144 | url: "https://pub.flutter-io.cn" 145 | source: hosted 146 | version: "0.1.2" 147 | plugin_platform_interface: 148 | dependency: transitive 149 | description: 150 | name: plugin_platform_interface 151 | url: "https://pub.flutter-io.cn" 152 | source: hosted 153 | version: "2.1.4" 154 | sky_engine: 155 | dependency: transitive 156 | description: flutter 157 | source: sdk 158 | version: "0.0.99" 159 | source_span: 160 | dependency: transitive 161 | description: 162 | name: source_span 163 | url: "https://pub.flutter-io.cn" 164 | source: hosted 165 | version: "1.9.0" 166 | stack_trace: 167 | dependency: transitive 168 | description: 169 | name: stack_trace 170 | url: "https://pub.flutter-io.cn" 171 | source: hosted 172 | version: "1.10.0" 173 | stream_channel: 174 | dependency: transitive 175 | description: 176 | name: stream_channel 177 | url: "https://pub.flutter-io.cn" 178 | source: hosted 179 | version: "2.1.0" 180 | string_scanner: 181 | dependency: transitive 182 | description: 183 | name: string_scanner 184 | url: "https://pub.flutter-io.cn" 185 | source: hosted 186 | version: "1.1.1" 187 | term_glyph: 188 | dependency: transitive 189 | description: 190 | name: term_glyph 191 | url: "https://pub.flutter-io.cn" 192 | source: hosted 193 | version: "1.2.1" 194 | test_api: 195 | dependency: transitive 196 | description: 197 | name: test_api 198 | url: "https://pub.flutter-io.cn" 199 | source: hosted 200 | version: "0.4.12" 201 | vector_math: 202 | dependency: transitive 203 | description: 204 | name: vector_math 205 | url: "https://pub.flutter-io.cn" 206 | source: hosted 207 | version: "2.1.2" 208 | visibility_detector: 209 | dependency: transitive 210 | description: 211 | name: visibility_detector 212 | url: "https://pub.flutter-io.cn" 213 | source: hosted 214 | version: "0.4.0+2" 215 | sdks: 216 | dart: ">=2.17.0 <3.0.0" 217 | flutter: ">=3.1.0-0" 218 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_gromore_example 2 | description: Demonstrates how to use the flutter_gromore plugin. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `flutter pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | environment: 9 | sdk: ">=2.12.0 <3.0.0" 10 | 11 | # Dependencies specify other packages that your package needs in order to work. 12 | # To automatically upgrade your package dependencies to the latest versions 13 | # consider running `flutter pub upgrade --major-versions`. Alternatively, 14 | # dependencies can be manually updated by changing the version numbers below to 15 | # the latest version available on pub.dev. To see which dependencies have newer 16 | # versions available, run `flutter pub outdated`. 17 | dependencies: 18 | flutter: 19 | sdk: flutter 20 | 21 | flutter_gromore: 22 | # When depending on this package from a real application you should use: 23 | # flutter_gromore: ^x.y.z 24 | # See https://dart.dev/tools/pub/dependencies#version-constraints 25 | # The example app is bundled with the plugin so we use a path dependency on 26 | # the parent directory to use the current plugin's version. 27 | path: ../ 28 | 29 | # The following adds the Cupertino Icons font to your application. 30 | # Use with the CupertinoIcons class for iOS style icons. 31 | cupertino_icons: ^1.0.2 32 | permission_handler: 10.0.2 33 | 34 | dev_dependencies: 35 | flutter_test: 36 | sdk: flutter 37 | 38 | # The "flutter_lints" package below contains a set of recommended lints to 39 | # encourage good coding practices. The lint set provided by the package is 40 | # activated in the `analysis_options.yaml` file located at the root of your 41 | # package. See that file for information about deactivating specific lint 42 | # rules and activating additional ones. 43 | flutter_lints: ^1.0.0 44 | 45 | # For information on the generic Dart part of this file, see the 46 | # following page: https://dart.dev/tools/pub/pubspec 47 | 48 | # The following section is specific to Flutter. 49 | flutter: 50 | 51 | # The following line ensures that the Material Icons font is 52 | # included with your application, so that you can use the icons in 53 | # the material Icons class. 54 | uses-material-design: true 55 | 56 | # To add assets to your application, add an assets section, like this: 57 | # assets: 58 | # - images/a_dot_burr.jpeg 59 | # - images/a_dot_ham.jpeg 60 | 61 | # An image asset can refer to one or more resolution-specific "variants", see 62 | # https://flutter.dev/assets-and-images/#resolution-aware. 63 | 64 | # For details regarding adding assets from package dependencies, see 65 | # https://flutter.dev/assets-and-images/#from-packages 66 | 67 | # To add custom fonts to your application, add a fonts section here, 68 | # in this "flutter" section. Each entry in this list should have a 69 | # "family" key with the font family name, and a "fonts" key with a 70 | # list giving the asset and other descriptors for the font. For 71 | # example: 72 | # fonts: 73 | # - family: Schyler 74 | # fonts: 75 | # - asset: fonts/Schyler-Regular.ttf 76 | # - asset: fonts/Schyler-Italic.ttf 77 | # style: italic 78 | # - family: Trajan Pro 79 | # fonts: 80 | # - asset: fonts/TrajanPro.ttf 81 | # - asset: fonts/TrajanPro_Bold.ttf 82 | # weight: 700 83 | # 84 | # For details regarding fonts from package dependencies, 85 | # see https://flutter.dev/custom-fonts/#from-packages 86 | -------------------------------------------------------------------------------- /example/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:flutter_gromore_example/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Verify Platform version', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(const MyApp()); 17 | 18 | // Verify that platform version is retrieved. 19 | expect( 20 | find.byWidgetPredicate( 21 | (Widget widget) => 22 | widget is Text && widget.data!.startsWith('Running on:'), 23 | ), 24 | findsOneWidget, 25 | ); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /flutter_gromore.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | /Flutter/ephemeral/ 38 | /Flutter/flutter_export_environment.sh -------------------------------------------------------------------------------- /ios/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/ios/Assets/.gitkeep -------------------------------------------------------------------------------- /ios/Classes/FlutterGromorePlugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface FlutterGromorePlugin : NSObject 4 | @end 5 | -------------------------------------------------------------------------------- /ios/Classes/FlutterGromorePlugin.m: -------------------------------------------------------------------------------- 1 | #import "FlutterGromorePlugin.h" 2 | #if __has_include() 3 | #import 4 | #else 5 | // Support project import fallback if the generated compatibility header 6 | // is not copied when this plugin is created as a library. 7 | // https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816 8 | #import "flutter_gromore-Swift.h" 9 | #endif 10 | 11 | @implementation FlutterGromorePlugin 12 | + (void)registerWithRegistrar:(NSObject*)registrar { 13 | [SwiftFlutterGromorePlugin registerWithRegistrar:registrar]; 14 | } 15 | @end 16 | -------------------------------------------------------------------------------- /ios/Classes/SwiftFlutterGromorePlugin.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import AppTrackingTransparency 4 | import BUAdSDK 5 | 6 | public class SwiftFlutterGromorePlugin: NSObject, FlutterPlugin { 7 | private static var messenger: FlutterBinaryMessenger? = nil 8 | private var splashAd: FlutterGromoreSplash? 9 | private var interstitialManager: FlutterGromoreInterstitialManager? 10 | private var rewardManager: FlutterGromoreRewardManager? 11 | private var interstitialFullAd: FlutterGromoreInterstitial? 12 | private var rewardAd: FlutterGromoreReward? 13 | private var initResuleCalled: Bool = false 14 | 15 | public static func register(with registrar: FlutterPluginRegistrar) { 16 | let channel = FlutterMethodChannel(name: FlutterGromoreContants.methodChannelName, binaryMessenger: registrar.messenger()) 17 | let eventChanel = FlutterEventChannel(name: FlutterGromoreContants.eventChannelName, binaryMessenger: registrar.messenger()) 18 | eventChanel.setStreamHandler(AdEventHandler.instance) 19 | let instance = SwiftFlutterGromorePlugin() 20 | 21 | messenger = registrar.messenger() 22 | registrar.addMethodCallDelegate(instance, channel: channel) 23 | registrar.register(FlutterGromoreFactory(messenger: registrar.messenger()), withId: FlutterGromoreContants.feedViewTypeId) 24 | registrar.register(FlutterGromoreBannerFactory(messenger: registrar.messenger()), withId: FlutterGromoreContants.bannerTypeId) 25 | 26 | } 27 | 28 | public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { 29 | let args = call.arguments as? Dictionary ?? [:] 30 | switch call.method { 31 | case "requestATT": 32 | requestATT(result: result) 33 | case "initSDK": 34 | initSDK(appId: args["appId"] as! String, result: result, debug: args["debug"] as? Bool ?? true, useMediation: args["useMediation"] as? Bool ?? false, themeStatus: args["themeStatus"] as? Int ?? 0) 35 | case "showSplashAd": 36 | splashAd = FlutterGromoreSplash(args: args, result: result) 37 | case "loadInterstitialAd": 38 | interstitialManager = FlutterGromoreInterstitialManager(args: args, result: result) 39 | interstitialManager?.loadAd() 40 | case "showInterstitialAd": 41 | interstitialFullAd = FlutterGromoreInterstitial(messenger: SwiftFlutterGromorePlugin.messenger!, arguments: args, result: result) 42 | case "removeInterstitialAd": 43 | removeInterstitialAd(args: args, result: result) 44 | case "loadFeedAd": 45 | let feedManager = FlutterGromoreFeedManager(args: args, result: result) 46 | feedManager.loadAd() 47 | case "removeFeedAd": 48 | removeFeedAd(args: args, result: result) 49 | case "loadRewardAd": 50 | rewardManager = FlutterGromoreRewardManager(args: args, result: result) 51 | rewardManager?.loadAd() 52 | case "showRewardAd": 53 | rewardAd = FlutterGromoreReward(messenger: SwiftFlutterGromorePlugin.messenger!, arguments: args, result: result) 54 | default: 55 | result(FlutterMethodNotImplemented) 56 | } 57 | } 58 | 59 | // 请求广告标识符 60 | private func requestATT(result: @escaping FlutterResult){ 61 | // iOS 14 之后需要获取 ATT 追踪权限 62 | if #available(iOS 14, *) { 63 | ATTrackingManager.requestTrackingAuthorization(completionHandler: { status in 64 | let isAuthorized: Bool = status == ATTrackingManager.AuthorizationStatus.authorized 65 | result(isAuthorized) 66 | }) 67 | } else { 68 | result(true) 69 | } 70 | } 71 | 72 | // 初始化SDK 73 | private func initSDK(appId: String, result: @escaping FlutterResult, debug: Bool, useMediation: Bool, themeStatus: Int) { 74 | 75 | // 已经开始初始化 76 | if (BUAdSDKManager.state == BUAdSDKState.start) { 77 | result(false) 78 | return 79 | } 80 | 81 | let config = BUAdSDKConfiguration.configuration() 82 | config.appID = appId 83 | config.debugLog = debug ? 1 : 0 84 | config.useMediation = useMediation 85 | config.themeStatus = (themeStatus) as NSNumber 86 | 87 | BUAdSDKManager.start(asyncCompletionHandler: {success, error in 88 | // 已经回调 89 | if (self.initResuleCalled) { 90 | return 91 | } 92 | if success { 93 | self.initResuleCalled = true 94 | result(true) 95 | } else { 96 | self.initResuleCalled = true 97 | result(FlutterError(code: "0", message: error?.localizedDescription ?? "", details: error?.localizedDescription ?? "")) 98 | } 99 | }) 100 | } 101 | 102 | /// 移除缓存中信息流广告 103 | private func removeFeedAd(args: [String: Any], result: @escaping FlutterResult) { 104 | if let feedId = args["feedId"] as? String { 105 | FlutterGromoreFeedCache.removeAd(key: feedId) 106 | } 107 | result(true) 108 | } 109 | 110 | /// 移除缓存中插屏广告 111 | private func removeInterstitialAd(args: [String: Any], result: @escaping FlutterResult) { 112 | if let interstitialId = args["interstitialId"] as? String { 113 | FlutterGromoreInterstitialCache.removeAd(key: interstitialId) 114 | } 115 | result(true) 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /ios/Classes/constants/FlutterGromoreConstants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FlutterGromoreConstants.swift 3 | // flutter_gromore 4 | // 5 | // Created by jlq on 2022/5/30. 6 | // 7 | 8 | import Foundation 9 | 10 | struct FlutterGromoreContants { 11 | // 事件名 12 | static let methodChannelName = "flutter_gromore" 13 | static let eventChannelName = "flutter_gromore_event" 14 | 15 | // viewTypeId 16 | static let feedViewTypeId = "flutter_gromore_feed" 17 | 18 | // 插屏 19 | static let interstitialTypeId = "flutter_gromore_interstitial" 20 | 21 | // 激励视频 22 | static let rewardTypeId = "flutter_gromore_reward" 23 | 24 | // banner广告 25 | static let bannerTypeId = "flutter_gromore_banner" 26 | } 27 | -------------------------------------------------------------------------------- /ios/Classes/event/AdEvent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AdEvent.swift 3 | // flutter_gromore 4 | // 5 | // Created by Anand on 2022/6/2. 6 | // 7 | 8 | class AdEvent: NSObject { 9 | private var id: String 10 | private var name: String 11 | 12 | init(id: String, name: String) { 13 | self.id = id 14 | self.name = name 15 | } 16 | 17 | func toMap() -> [String: String] { 18 | return [ 19 | "id": id, 20 | "name": name 21 | ] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Classes/event/AdEventHandler.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AdEventHandler.swift 3 | // flutter_gromore 4 | // 5 | // Created by Anand on 2022/6/2. 6 | // 7 | 8 | class AdEventHandler: NSObject, FlutterStreamHandler { 9 | static let instance: AdEventHandler = AdEventHandler() 10 | private var eventSink: FlutterEventSink? 11 | 12 | func sendEvent(_ event: AdEvent) { 13 | if let sink = eventSink { 14 | sink(event.toMap()) 15 | } 16 | } 17 | 18 | func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { 19 | eventSink = events 20 | return nil 21 | } 22 | 23 | func onCancel(withArguments arguments: Any?) -> FlutterError? { 24 | eventSink = nil 25 | return nil 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ios/Classes/factory/FlutterGromoreBannerFactory.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FlutterGromoreBannerFactory.swift 3 | // flutter_gromore 4 | // 5 | // Created by Stahsf on 2023/6/24. 6 | // 7 | 8 | import Foundation 9 | 10 | class FlutterGromoreBannerFactory: NSObject, FlutterPlatformViewFactory { 11 | 12 | private var messenger: FlutterBinaryMessenger 13 | 14 | init(messenger: FlutterBinaryMessenger) { 15 | self.messenger = messenger 16 | } 17 | 18 | func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView { 19 | return FlutterGromoreBanner(frame: frame, id: viewId, params: args, messenger: messenger) 20 | } 21 | 22 | func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol { 23 | FlutterStandardMessageCodec.sharedInstance() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ios/Classes/factory/FlutterGromoreFeedFactory.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FlutterGromoreFeedFactory.swift 3 | // flutter_gromore 4 | // 5 | // Created by jlq on 2022/5/31. 6 | // 7 | 8 | import Foundation 9 | class FlutterGromoreFactory: NSObject, FlutterPlatformViewFactory { 10 | 11 | private var messenger: FlutterBinaryMessenger 12 | 13 | init(messenger: FlutterBinaryMessenger) { 14 | self.messenger = messenger 15 | } 16 | 17 | func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView { 18 | return FlutterGromoreFeed(frame: frame, id: viewId, params: args, messenger: messenger) 19 | } 20 | 21 | func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol { 22 | FlutterStandardMessageCodec.sharedInstance() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ios/Classes/manager/FlutterGromoreFeedCache.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FlutterGromoreFeedCache.swift 3 | // flutter_gromore 4 | // 5 | // Created by Anand on 2022/6/7. 6 | // 7 | 8 | import BUAdSDK 9 | 10 | class FlutterGromoreFeedCache: NSObject { 11 | private static var ads: [String: BUNativeAd] = [:] 12 | private static var adManager: [String: FlutterGromoreFeedManager] = [:] 13 | 14 | static func addAd(_ id: String,_ ad: BUNativeAd) { 15 | ads[id] = ad 16 | } 17 | 18 | static func removeAd(key: String) { 19 | ads.removeValue(forKey: key) 20 | // 移除manager引用 -> 当一个manager实例不被引用时会自动销毁 21 | adManager.removeValue(forKey: key) 22 | } 23 | 24 | static func getAd(key: String) -> BUNativeAd? { 25 | return ads[key] 26 | } 27 | 28 | // 保存引用。key为manager引用地址,value为对应的manager实例 29 | static func addManager(_ id: String,_ manager: FlutterGromoreFeedManager) { 30 | adManager[id] = manager 31 | } 32 | 33 | // 更新引用,更新后:key为广告id,value为对应的manager实例。这里的目的是方便后面在广告回调中移除 34 | static func updateManager(managerAddress: String, adAddress: String) { 35 | let manager = adManager[managerAddress] 36 | adManager.removeValue(forKey: managerAddress) 37 | adManager[adAddress] = manager 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ios/Classes/manager/FlutterGromoreFeedManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FlutterGromoreFeedManager.swift 3 | // flutter_gromore 4 | // 5 | // Created by Anand on 2022/6/7. 6 | // 7 | 8 | import Foundation 9 | import BUAdSDK 10 | 11 | class FlutterGromoreFeedManager: NSObject, BUNativeAdsManagerDelegate { 12 | 13 | private var args: [String: Any] 14 | private var result: FlutterResult 15 | private var manager: BUNativeAdsManager? 16 | 17 | init(args: [String: Any], result: @escaping FlutterResult) { 18 | self.args = args 19 | self.result = result 20 | } 21 | 22 | deinit { 23 | manager?.mediation?.destory() 24 | } 25 | 26 | func loadAd() { 27 | let adUnitId: String = args["adUnitId"] as! String 28 | let adSize: CGSize = CGSize( 29 | width: args["width"] as? CGFloat ?? UIScreen.main.bounds.size.width, 30 | // 高度默认为零使用自适应 31 | height: args["height"] as? CGFloat ?? 0 32 | ) 33 | let buSize = BUSize() 34 | buSize.width = 1080; 35 | buSize.height = 1920 36 | 37 | let slot: BUAdSlot = BUAdSlot() 38 | slot.id = adUnitId 39 | slot.adSize = adSize 40 | // 静音播放 41 | slot.mediation.mutedIfCan = true 42 | 43 | manager = BUNativeAdsManager.init(slot: slot) 44 | 45 | manager?.delegate = self 46 | manager?.mediation?.rootViewController = Utils.getVC() 47 | manager?.loadAdData(withCount: args["count"] as? Int ?? 3) 48 | 49 | // 保存引用,不让实例销毁。如果销毁了的话广告的某些事件回调不会触发(巨坑!) 50 | FlutterGromoreFeedCache.addManager(String(self.hash), self) 51 | } 52 | 53 | func nativeAdsManagerSuccess(toLoad adsManager: BUNativeAdsManager, nativeAds nativeAdDataArray: [BUNativeAd]?) { 54 | // 将广告视图的 Key 返回给 Flutter 端 55 | var adsKey: [String] = [] 56 | let adUnitId: String = args["adUnitId"] as! String 57 | if let ads = nativeAdDataArray { 58 | ads.forEach { ad in 59 | let adId: String = "\(adUnitId)_\(ad.hash)" 60 | adsKey.append(adId) 61 | // 将广告存下来 62 | FlutterGromoreFeedCache.addAd(adId, ad) 63 | FlutterGromoreFeedCache.updateManager(managerAddress: String(self.hash), adAddress: adId) 64 | } 65 | } 66 | 67 | result(adsKey) 68 | } 69 | 70 | func nativeAdsManagerDidFinishLoadAdnAd(_ adsManager: BUNativeAdsManager, nativeAd: BUNativeAd?, error: Error?) { 71 | result(FlutterError(code: "0", message: error?.localizedDescription ?? "", details: error?.localizedDescription ?? "")) 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /ios/Classes/manager/FlutterGromoreInterstitialCache.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FlutterGromoreInterstitialCache.swift 3 | // flutter_gromore 4 | // 5 | // Created by jlq on 2022/6/16. 6 | // 7 | 8 | import Foundation 9 | import BUAdSDK 10 | 11 | class FlutterGromoreInterstitialCache: NSObject { 12 | private static var ads: [String: BUNativeExpressFullscreenVideoAd] = [:] 13 | 14 | static func addAd(key: String, ad: BUNativeExpressFullscreenVideoAd) { 15 | ads[key] = ad 16 | } 17 | 18 | static func removeAd(key: String) { 19 | ads.removeValue(forKey: key) 20 | } 21 | 22 | static func getAd(key: String) -> BUNativeExpressFullscreenVideoAd? { 23 | return ads[key] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ios/Classes/manager/FlutterGromoreInterstitialManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FlutterGromoreInterstitialManager.swift 3 | // flutter_gromore 4 | // 5 | // Created by jlq on 2022/6/16. 6 | // 7 | 8 | import Foundation 9 | import BUAdSDK 10 | 11 | class FlutterGromoreInterstitialManager: NSObject, BUNativeExpressFullscreenVideoAdDelegate { 12 | private var args: [String: Any] 13 | private var result: FlutterResult 14 | private var interstitialAd: BUNativeExpressFullscreenVideoAd? 15 | 16 | init(args: [String: Any], result: @escaping FlutterResult) { 17 | self.args = args 18 | self.result = result 19 | } 20 | 21 | func loadAd() { 22 | let adUnitId: String = args["adUnitId"] as! String 23 | 24 | let slot = BUAdSlot() 25 | slot.mediation.mutedIfCan = args["muted"] as? Bool ?? true 26 | slot.id = adUnitId 27 | interstitialAd = BUNativeExpressFullscreenVideoAd(slot: slot) 28 | if let ad = interstitialAd { 29 | ad.delegate = self 30 | ad.loadData() 31 | } 32 | } 33 | 34 | // 加载成功 35 | func nativeExpressFullscreenVideoAdDidLoad(_ fullscreenVideoAd: BUNativeExpressFullscreenVideoAd) { 36 | let id = String(fullscreenVideoAd.hashValue) 37 | FlutterGromoreInterstitialCache.addAd(key: id, ad: fullscreenVideoAd) 38 | result(id) 39 | } 40 | 41 | // 加载失败 42 | func nativeExpressFullscreenVideoAd(_ fullscreenVideoAd: BUNativeExpressFullscreenVideoAd, didFailWithError error: Error?) { 43 | result(FlutterError(code: "0", message: error?.localizedDescription ?? "", details: error?.localizedDescription ?? "")) 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /ios/Classes/manager/FlutterGromoreRewardCache.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FlutterGromoreRewardCache.swift 3 | // flutter_gromore 4 | // 5 | // Created by Stahsf on 2023/6/13. 6 | // 7 | 8 | import Foundation 9 | import BUAdSDK 10 | 11 | class FlutterGromoreRewardCache: NSObject { 12 | private static var ads: [String: BUNativeExpressRewardedVideoAd] = [:] 13 | 14 | static func addAd(key: String, ad: BUNativeExpressRewardedVideoAd) { 15 | ads[key] = ad 16 | } 17 | 18 | static func removeAd(key: String) { 19 | ads.removeValue(forKey: key) 20 | } 21 | 22 | static func getAd(key: String) -> BUNativeExpressRewardedVideoAd? { 23 | return ads[key] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ios/Classes/manager/FlutterGromoreRewardManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FlutterGromoreRewardManager.swift 3 | // flutter_gromore 4 | // 5 | // Created by Stahsf on 2023/6/13. 6 | // 7 | 8 | import Foundation 9 | import BUAdSDK 10 | 11 | class FlutterGromoreRewardManager: NSObject, BUNativeExpressRewardedVideoAdDelegate { 12 | private var args: [String: Any] 13 | private var result: FlutterResult 14 | private var rewardAd: BUNativeExpressRewardedVideoAd? 15 | 16 | init(args: [String: Any], result: @escaping FlutterResult) { 17 | self.args = args 18 | self.result = result 19 | } 20 | 21 | func loadAd() { 22 | let adUnitId: String = args["adUnitId"] as! String 23 | 24 | let slot = BUAdSlot() 25 | slot.mediation.mutedIfCan = args["muted"] as? Bool ?? true 26 | slot.id = adUnitId 27 | 28 | let model = BURewardedVideoModel() 29 | rewardAd = BUNativeExpressRewardedVideoAd.init(slot: slot, rewardedVideoModel: model) 30 | if let ad = rewardAd { 31 | ad.delegate = self 32 | ad.loadData() 33 | } 34 | } 35 | 36 | // 加载成功 37 | func nativeExpressRewardedVideoAdDidLoad(_ rewardedVideoAd: BUNativeExpressRewardedVideoAd) { 38 | let id = String(rewardedVideoAd.hashValue) 39 | FlutterGromoreRewardCache.addAd(key: id, ad: rewardedVideoAd) 40 | result(id) 41 | } 42 | 43 | // 加载失败 44 | func nativeExpressRewardedVideoAd(_ rewardedVideoAd: BUNativeExpressRewardedVideoAd, didFailWithError error: Error?) { 45 | result(FlutterError(code: "0", message: error?.localizedDescription ?? "", details: error?.localizedDescription ?? "")) 46 | } 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /ios/Classes/utils/GCDTool.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GCDTool.swift 3 | // flutter_gromore 4 | // 5 | // Created by Stahsf on 2023/7/20. 6 | // 7 | 8 | import Foundation 9 | 10 | typealias GCDTask = (_ cancel: Bool) -> () 11 | 12 | class GCDTool: NSObject { 13 | 14 | @discardableResult static func gcdDelay(_ time: TimeInterval, task: @escaping () -> ()) -> GCDTask?{ 15 | 16 | func dispatch_later(block: @escaping () -> ()) { 17 | let t = DispatchTime.now() + time 18 | DispatchQueue.main.asyncAfter(deadline: t, execute: block) 19 | } 20 | 21 | var closure: (() -> Void)? = task 22 | var result: GCDTask? 23 | 24 | let delayedClosure: GCDTask = { 25 | cancel in 26 | if let closure = closure { 27 | if !cancel { 28 | DispatchQueue.main.async(execute: closure) 29 | } 30 | } 31 | closure = nil 32 | result = nil 33 | } 34 | 35 | result = delayedClosure 36 | 37 | dispatch_later { 38 | if let result = result { 39 | result(false) 40 | } 41 | } 42 | 43 | return result 44 | } 45 | 46 | static func gcdCancel(_ task: GCDTask?) { 47 | task?(true) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ios/Classes/utils/Utils.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Utils.swift 3 | // flutter_gromore 4 | // 5 | // Created by jlq on 2022/5/31. 6 | // 7 | 8 | import Foundation 9 | 10 | class Utils { 11 | // 获取ViewController 12 | static func getVC() -> UIViewController { 13 | let viewController = UIApplication.shared.windows.filter({ (w) -> Bool in 14 | w.isHidden == false 15 | }).first?.rootViewController 16 | 17 | return viewController! 18 | } 19 | 20 | static var getScreenWidth: Int { 21 | return Int(floor(UIScreen.main.bounds.width)) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Classes/view/FlutterGromoreBanner.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FlutterGromoreBanner.swift 3 | // flutter_gromore 4 | // 5 | // Created by Stahsf on 2023/6/24. 6 | // 7 | 8 | import Foundation 9 | import BUAdSDK 10 | 11 | class FlutterGromoreBanner: NSObject, FlutterPlatformView, BUNativeExpressBannerViewDelegate { 12 | 13 | 14 | var methodChannel: FlutterMethodChannel 15 | /// 容器 16 | private var container: FlutterGromoreIntercptPenetrateView 17 | /// 传递过来的参数 18 | private var createParams: [String: Any] 19 | 20 | private var bannerAd: BUNativeExpressBannerView? 21 | 22 | init(frame: CGRect, id: Int64, params: Any?, messenger: FlutterBinaryMessenger) { 23 | methodChannel = FlutterMethodChannel(name: "\(FlutterGromoreContants.bannerTypeId)/\(id)", binaryMessenger: messenger) 24 | container = FlutterGromoreIntercptPenetrateView(frame: frame, methodChannel: methodChannel) 25 | createParams = params as? [String : Any] ?? [:] 26 | super.init() 27 | initAd() 28 | } 29 | 30 | func initAd() { 31 | print("FlutterGromoreBanner initAd ") 32 | let adUnitId: String = createParams["adUnitId"] as! String 33 | var width: CGFloat = 0 34 | var height: CGFloat = 0 35 | 36 | if createParams["width"] != nil { 37 | width = CGFloat(Float(createParams["width"] as! Double)) 38 | } else { 39 | width = UIScreen.main.bounds.size.width 40 | } 41 | 42 | if createParams["height"] != nil { 43 | height = CGFloat(Float(createParams["height"] as! Double)) 44 | } else { 45 | height = 150 46 | } 47 | 48 | 49 | let adSize: CGSize = CGSize( 50 | width: width, 51 | // 高度默认为150 52 | height: height 53 | ) 54 | let buSize = BUSize() 55 | buSize.width = 1080 56 | buSize.height = 1920 57 | 58 | let slot: BUAdSlot = BUAdSlot() 59 | slot.id = adUnitId 60 | slot.adSize = adSize 61 | // 静音播放 62 | slot.mediation.mutedIfCan = true 63 | 64 | bannerAd = BUNativeExpressBannerView.init(slot: slot, rootViewController: Utils.getVC(), adSize: adSize) 65 | bannerAd?.frame = CGRectMake(0, 0, adSize.width, adSize.height) 66 | bannerAd?.delegate = self 67 | bannerAd?.loadAdData() 68 | } 69 | 70 | private func postMessage(_ method: String, arguments: Any? = nil) { 71 | methodChannel.invokeMethod(method, arguments: arguments) 72 | } 73 | 74 | func view() -> UIView { 75 | container 76 | } 77 | 78 | deinit { 79 | print("FlutterGromoreBanner deinit"); 80 | removeAdView() 81 | } 82 | 83 | func removeAdView() { 84 | for v: UIView in container.subviews { 85 | v.removeFromSuperview() 86 | } 87 | bannerAd?.removeFromSuperview() 88 | bannerAd = nil 89 | } 90 | 91 | // 加载成功 92 | func nativeExpressBannerAdViewDidLoad(_ bannerAdView: BUNativeExpressBannerView) { 93 | print("FlutterGromoreBanner nativeExpressBannerAdViewDidLoad") 94 | container.clipsToBounds = true 95 | container.addSubview(bannerAd!) 96 | postMessage("onRenderSuccess") 97 | 98 | container.isPermeable = true 99 | } 100 | 101 | // 加载失败 102 | func nativeExpressBannerAdView(_ bannerAdView: BUNativeExpressBannerView, didLoadFailWithError error: Error?) { 103 | postMessage("onLoadError") 104 | } 105 | 106 | // 渲染成功 107 | func nativeExpressBannerAdViewRenderSuccess(_ bannerAdView: BUNativeExpressBannerView) { 108 | } 109 | 110 | // 被强制移除 111 | func nativeExpressBannerAdViewDidRemoved(_ bannerAdView: BUNativeExpressBannerView) { 112 | postMessage("onAdTerminate") 113 | } 114 | 115 | // 选择关闭原因 116 | func nativeExpressBannerAdView(_ bannerAdView: BUNativeExpressBannerView, dislikeWithReason filterwords: [BUDislikeWords]?) { 117 | removeAdView() 118 | postMessage("onSelected") 119 | } 120 | 121 | // 点击 122 | func nativeExpressBannerAdViewDidClick(_ bannerAdView: BUNativeExpressBannerView) { 123 | postMessage("onAdClick") 124 | } 125 | 126 | // 展示 127 | func nativeExpressBannerAdViewWillBecomVisible(_ bannerAdView: BUNativeExpressBannerView) { 128 | postMessage("onAdShow") 129 | } 130 | 131 | // 渲染失败 132 | func nativeExpressBannerAdViewRenderFail(_ bannerAdView: BUNativeExpressBannerView, error: Error?) { 133 | postMessage("onRenderFail") 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /ios/Classes/view/FlutterGromoreBase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FlutterGromoreBase.swift 3 | // flutter_gromore 4 | // 5 | // Created by jlq on 2022/6/1. 6 | // 7 | 8 | import Foundation 9 | 10 | protocol FlutterGromoreBase { 11 | var methodChannel: FlutterMethodChannel? { get set } 12 | /// 初始化广告 13 | func initAd() 14 | } 15 | 16 | extension FlutterGromoreBase { 17 | 18 | func initMethodChannel(channelName: String, messenger: FlutterBinaryMessenger) -> FlutterMethodChannel? { 19 | let methodChannel = FlutterMethodChannel(name: channelName, binaryMessenger: messenger) 20 | return methodChannel 21 | } 22 | 23 | func postMessage(_ method: String, arguments: Any? = nil) { 24 | methodChannel?.invokeMethod(method, arguments: arguments) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ios/Classes/view/FlutterGromoreFeed.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FlutterGromoreFeed.swift 3 | // flutter_gromore 4 | // 5 | // Created by jlq on 2022/5/31. 6 | // 7 | 8 | import Foundation 9 | import BUAdSDK 10 | 11 | class FlutterGromoreFeed: NSObject, FlutterPlatformView, BUMNativeAdDelegate { 12 | 13 | 14 | var methodChannel: FlutterMethodChannel 15 | /// 容器 16 | private var container: FlutterGromoreIntercptPenetrateView 17 | /// 传递过来的参数 18 | private var createParams: [String: Any] 19 | 20 | private var feedAd: BUNativeAd? 21 | 22 | init(frame: CGRect, id: Int64, params: Any?, messenger: FlutterBinaryMessenger) { 23 | methodChannel = FlutterMethodChannel(name: "\(FlutterGromoreContants.feedViewTypeId)/\(id)", binaryMessenger: messenger) 24 | container = FlutterGromoreIntercptPenetrateView(frame: frame, methodChannel: methodChannel) 25 | createParams = params as? [String : Any] ?? [:] 26 | super.init() 27 | initAd() 28 | } 29 | 30 | func initAd() { 31 | let adViewId: String = createParams["feedId"] as! String 32 | if let ad: BUNativeAd = FlutterGromoreFeedCache.getAd(key: adViewId) { 33 | ad.rootViewController = Utils.getVC() 34 | ad.delegate = self 35 | if ad.mediation?.isExpressAd ?? false { 36 | feedAd = ad 37 | ad.mediation?.render() 38 | } 39 | } 40 | } 41 | 42 | private func postMessage(_ method: String, arguments: Any? = nil) { 43 | methodChannel.invokeMethod(method, arguments: arguments) 44 | } 45 | 46 | func view() -> UIView { 47 | container 48 | } 49 | 50 | deinit { 51 | removeAdView() 52 | } 53 | 54 | func removeAdView() { 55 | for v: UIView in container.subviews { 56 | v.removeFromSuperview() 57 | } 58 | let adId: String = createParams["feedId"] as! String 59 | FlutterGromoreFeedCache.removeAd(key: adId) 60 | } 61 | 62 | func nativeAdWillPresentFullScreenModal(_ nativeAd: BUNativeAd) { 63 | } 64 | 65 | func nativeAdExpressViewRenderSuccess(_ nativeAd: BUNativeAd) { 66 | if let height = nativeAd.mediation?.canvasView.bounds.height { 67 | postMessage("onRenderSuccess", arguments: ["height": height]) 68 | 69 | container.frame.size.height = height 70 | container.clipsToBounds = true 71 | 72 | container.addSubview(nativeAd.mediation!.canvasView) 73 | } 74 | } 75 | 76 | func nativeAdExpressViewRenderFail(_ nativeAd: BUNativeAd, error: Error?) { 77 | postMessage("onRenderFail") 78 | } 79 | 80 | func nativeAdVideo(_ nativeAd: BUNativeAd?, stateDidChanged playerState: BUPlayerPlayState) { 81 | } 82 | 83 | func nativeAdVideoDidClick(_ nativeAd: BUNativeAd?) { 84 | postMessage("onAdClick") 85 | } 86 | 87 | func nativeAdVideoDidPlayFinish(_ nativeAd: BUNativeAd?) { 88 | } 89 | 90 | func nativeAdShakeViewDidDismiss(_ nativeAd: BUNativeAd?) { 91 | } 92 | 93 | func nativeAdVideo(_ nativeAdView: BUNativeAd?, rewardDidCountDown countDown: Int) { 94 | } 95 | 96 | 97 | func nativeAdDidClick(_ nativeAd: BUNativeAd, with view: UIView?) { 98 | postMessage("onAdClick") 99 | } 100 | 101 | 102 | func nativeAdDidBecomeVisible(_ nativeAd: BUNativeAd) { 103 | postMessage("onAdShow") 104 | container.isPermeable = true 105 | 106 | // if let adnName = nativeAd.mediation?.getShowEcpmInfo()?.adnName, adnName == "pangle" { 107 | // 穿山甲广告存在点击穿透 108 | // container.isPermeable = true 109 | // 穿山甲广告每次滑入视图时都会调用 “用户申请展示广告” 110 | // Guess: BUNativeExpressAdView 大概在 viewWillAppear 调用了展示广告,打算移除这一层 111 | // 层级结构:ABUNativeAdView -> BUNativeExpressAdView -> BUWKWebViewClient 112 | // 113 | // if let pangleNativeAdView = nativeAdView.subviews.first, 114 | // let pangleWebView = pangleNativeAdView.subviews.first { 115 | // pangleNativeAdView.removeFromSuperview() 116 | // nativeAdView.addSubview(pangleWebView) 117 | // } 118 | // } 119 | } 120 | 121 | func nativeAd(_ nativeAd: BUNativeAd?, dislikeWithReason filterWords: [BUDislikeWords]?) { 122 | postMessage("onSelected") 123 | nativeAd?.mediation?.canvasView.removeFromSuperview() 124 | removeAdView() 125 | } 126 | 127 | 128 | // 被强制关闭 129 | func nativeAd(_ nativeAd: BUNativeAd?, adContainerViewDidRemoved adContainerView: UIView) { 130 | postMessage("onAdTerminate") 131 | removeAdView() 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /ios/Classes/view/FlutterGromoreIntercptPenetrateView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FlutterGromoreIntercptPenetrateView.swift 3 | // flutter_gromore 4 | // 5 | // Created by Anand on 2022/6/13. 6 | // 7 | 8 | /// 用于拦截点击穿透 9 | class FlutterGromoreIntercptPenetrateView: UIView { 10 | /// 存在穿透问题? 11 | var isPermeable: Bool = false 12 | /// 广告是否被覆盖 13 | var isCovered: Bool = false 14 | /// 广告的可见区域 15 | var visibleBounds: CGRect = CGRect.zero 16 | 17 | init(frame: CGRect, methodChannel: FlutterMethodChannel) { 18 | super.init(frame: frame) 19 | methodChannel.setMethodCallHandler(handle(_:result:)) 20 | } 21 | 22 | required init?(coder: NSCoder) { 23 | super.init(coder: coder) 24 | } 25 | 26 | func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { 27 | switch call.method { 28 | case "updateVisibleBounds": 29 | let args: [String: Any] = call.arguments as! [String: Any] 30 | isCovered = args["isCovered"] as! Bool 31 | visibleBounds = CGRect(x: args["x"] as! Double, y: args["y"] as! Double, width: args["width"] as! Double, height: args["height"] as! Double) 32 | result(true) 33 | default: 34 | result(FlutterMethodNotImplemented) 35 | } 36 | } 37 | 38 | override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { 39 | if isPermeable, let overlay = getFlutterOverlayView() { 40 | // 在窗口的点击位置 41 | let windowPoint: CGPoint = convert(point, to: Utils.getVC().view) 42 | // 被覆盖时 -> 点击位置不在可见区域 43 | // 或 44 | // 点击位置在 PlatformView 被遮盖时形成的 FlutterOverlayView 上时阻断点击穿透 45 | // TODO: PlatformView 被遮盖一部分时无法被正常点击(形成了 FlutterOverlayView) 46 | if (isCovered && !visibleBounds.contains(windowPoint)) || overlay.frame.contains(windowPoint) { 47 | return false 48 | } 49 | } 50 | return true 51 | } 52 | 53 | // override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { 54 | // if !isUserInteractionEnabled || isHidden || alpha < 0.01 { 55 | // return nil 56 | // } 57 | // 58 | // return super.hitTest(point, with: event) 59 | // } 60 | 61 | /// 获取 PlatformView 渲染的 FlutterOverlayView 视图 62 | /// 当 PlatformView 被 Widget 覆盖时,FlutterOverlayView 会进行绘制 63 | private func getFlutterOverlayView() -> UIView? { 64 | // PlatformView 渲染后的层级:FlutterView -> ChildClippingView -> FlutterTouchInterceptingView -> 当前视图 65 | // FlutterOverlayView 和 ChildClippingView 同级 66 | if let views = superview?.superview?.superview?.subviews { 67 | for view in views.reversed() { 68 | if String(describing: view).contains("FlutterOverlayView") { 69 | return view 70 | } 71 | } 72 | } 73 | return nil 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /ios/Classes/view/FlutterGromoreInterstitial.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FlutterGromoreInterstitial.swift 3 | // flutter_gromore 4 | // 5 | // Created by jlq on 2022/6/1. 6 | // 7 | 8 | import BUAdSDK 9 | 10 | class FlutterGromoreInterstitial: NSObject, FlutterGromoreBase, BUNativeExpressFullscreenVideoAdDelegate { 11 | var methodChannel: FlutterMethodChannel? 12 | private var args: [String: Any] 13 | private var interstitialAd: BUNativeExpressFullscreenVideoAd? 14 | private var result: FlutterResult 15 | private var interstitialId: String = "" 16 | 17 | init(messenger: FlutterBinaryMessenger, arguments: [String: Any], result: @escaping FlutterResult) { 18 | args = arguments 19 | self.result = result 20 | super.init() 21 | interstitialId = arguments["interstitialId"] as! String 22 | interstitialAd = FlutterGromoreInterstitialCache.getAd(key: interstitialId) 23 | methodChannel = initMethodChannel(channelName: "\(FlutterGromoreContants.interstitialTypeId)/\(interstitialId)", messenger: messenger) 24 | initAd() 25 | } 26 | 27 | func initAd() { 28 | if let ad = interstitialAd, ad.mediation?.isReady ?? false { 29 | ad.delegate = self 30 | ad.show(fromRootViewController: Utils.getVC()) 31 | } 32 | } 33 | 34 | func destroyAd() { 35 | FlutterGromoreInterstitialCache.removeAd(key: interstitialId) 36 | interstitialAd = nil 37 | } 38 | 39 | // 展示插全屏广告 40 | func nativeExpressFullscreenVideoAdDidVisible(_ fullscreenVideoAd: BUNativeExpressFullscreenVideoAd) { 41 | postMessage("onInterstitialShow") 42 | } 43 | 44 | // 广告关闭 45 | func nativeExpressFullscreenVideoAdDidClose(_ fullscreenVideoAd: BUNativeExpressFullscreenVideoAd) { 46 | postMessage("onInterstitialClosed") 47 | result(true) 48 | destroyAd() 49 | } 50 | 51 | // 渲染失败 52 | func nativeExpressFullscreenVideoAdViewRenderFail(_ rewardedVideoAd: BUNativeExpressFullscreenVideoAd, error: Error?) { 53 | postMessage("onInterstitialShowFail") 54 | result(false) 55 | destroyAd() 56 | } 57 | 58 | // 点击 59 | func nativeExpressFullscreenVideoAdDidClick(_ fullscreenVideoAd: BUNativeExpressFullscreenVideoAd) { 60 | postMessage("onInterstitialAdClick") 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /ios/Classes/view/FlutterGromoreReward.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FlutterGromoreReward.swift 3 | // flutter_gromore 4 | // 5 | // Created by Stahsf on 2023/6/13. 6 | // 7 | 8 | import Foundation 9 | import BUAdSDK 10 | 11 | class FlutterGromoreReward: NSObject, FlutterGromoreBase, BUMNativeExpressRewardedVideoAdDelegate { 12 | var methodChannel: FlutterMethodChannel? 13 | private var args: [String: Any] 14 | private var rewardAd: BUNativeExpressRewardedVideoAd? 15 | private var result: FlutterResult 16 | private var rewardId: String = "" 17 | 18 | init(messenger: FlutterBinaryMessenger, arguments: [String: Any], result: @escaping FlutterResult) { 19 | args = arguments 20 | self.result = result 21 | super.init() 22 | rewardId = arguments["rewardId"] as! String 23 | rewardAd = FlutterGromoreRewardCache.getAd(key: rewardId) 24 | methodChannel = initMethodChannel(channelName: "\(FlutterGromoreContants.rewardTypeId)/\(rewardId)", messenger: messenger) 25 | initAd() 26 | } 27 | 28 | func initAd() { 29 | if let ad = rewardAd, ad.mediation?.isReady ?? false { 30 | ad.delegate = self 31 | ad.show(fromRootViewController: Utils.getVC()) 32 | } 33 | } 34 | 35 | func destroyAd() { 36 | FlutterGromoreRewardCache.removeAd(key: rewardId) 37 | rewardAd = nil 38 | } 39 | 40 | func nativeExpressRewardedVideoAdDidVisible(_ rewardedVideoAd: BUNativeExpressRewardedVideoAd) { 41 | postMessage("onAdShow") 42 | } 43 | 44 | func nativeExpressRewardedVideoAdDidClick(_ rewardedVideoAd: BUNativeExpressRewardedVideoAd) { 45 | postMessage("onAdVideoBarClick") 46 | } 47 | 48 | func nativeExpressRewardedVideoAdDidClose(_ rewardedVideoAd: BUNativeExpressRewardedVideoAd) { 49 | postMessage("onAdClose") 50 | result(true) 51 | destroyAd() 52 | } 53 | 54 | func nativeExpressRewardedVideoAdDidPlayFinish(_ rewardedVideoAd: BUNativeExpressRewardedVideoAd, didFailWithError error: Error?) { 55 | postMessage("onVideoComplete") 56 | } 57 | 58 | func nativeExpressRewardedVideoAdServerRewardDidFail(_ rewardedVideoAd: BUNativeExpressRewardedVideoAd, error: Error?) { 59 | postMessage("onVideoError") 60 | result(false) 61 | destroyAd() 62 | } 63 | 64 | func nativeExpressRewardedVideoAdServerRewardDidSucceed(_ rewardedVideoAd: BUNativeExpressRewardedVideoAd, verify: Bool) { 65 | postMessage("onRewardVerify", arguments: ["verify": verify]) 66 | } 67 | 68 | func nativeExpressRewardedVideoAdDidClickSkip(_ rewardedVideoAd: BUNativeExpressRewardedVideoAd) { 69 | postMessage("onSkippedVideo") 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /ios/Classes/view/FlutterGromoreSplash.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FlutterGromoreSplash.swift 3 | // flutter_gromore 4 | // 5 | // Created by Anand on 2022/5/31. 6 | // 7 | 8 | import BUAdSDK 9 | 10 | class FlutterGromoreSplash: NSObject, BUSplashAdDelegate { 11 | 12 | private var eventId: String? 13 | private var splashAd: BUSplashAd? 14 | private var result: FlutterResult 15 | 16 | // 自动关闭timer 17 | private var closeAdTimer: GCDTask? 18 | // 自动跳过timer 19 | private var skipAdTimer: GCDTask? 20 | 21 | // 结束标识,防止多次调用 22 | private var ended = false 23 | 24 | init(args: [String: Any], result: @escaping FlutterResult) { 25 | eventId = args["id"] as? String 26 | self.result = result 27 | super.init() 28 | initAd(args: args) 29 | } 30 | 31 | /// 初始化广告 32 | private func initAd(args: [String: Any]) { 33 | let slot = BUAdSlot() 34 | slot.id = args["adUnitId"] as! String 35 | slot.mediation.mutedIfCan = true 36 | slot.mediation.bidNotify = (args["bidNotify"] ?? false) as! Bool 37 | 38 | splashAd = BUSplashAd(slot: slot, adSize: CGSizeZero) 39 | splashAd?.delegate = self 40 | // 展示 logo 41 | let logo: String = args["logo"] as? String ?? "" 42 | if !logo.isEmpty { 43 | splashAd?.mediation?.customBottomView = generateLogoContainer(name: logo) 44 | } 45 | // 加载开屏广告 46 | splashAd?.loadData() 47 | 48 | // 6秒后广告未展示,延时自动关闭 49 | closeAdTimer = GCDTool.gcdDelay(6) { 50 | self.sendEvent("onAutoClose") 51 | self.splashEnd(false) 52 | } 53 | } 54 | 55 | /// 创建 logo 容器 56 | private func generateLogoContainer(name: String) -> UIView { 57 | // logo 图片 58 | let logoImage: UIView = UIImageView(image: UIImage(named: name)) 59 | // 容器 60 | let screenSize: CGSize = UIScreen.main.bounds.size 61 | let logoContainerWidth: CGFloat = screenSize.width 62 | let logoContainerHeight: CGFloat = screenSize.height * 0.15 63 | let logoContainer: UIView = UIView(frame: CGRect(x: 0, y: 0, width: logoContainerWidth, height: logoContainerHeight)) 64 | logoContainer.backgroundColor = UIColor.white 65 | // 居中 66 | logoImage.contentMode = UIView.ContentMode.center 67 | logoImage.center = logoContainer.center 68 | // 设置到开屏广告底部 69 | logoContainer.addSubview(logoImage) 70 | return logoContainer 71 | } 72 | 73 | private func sendEvent(_ message: String) { 74 | if let id = eventId { 75 | AdEventHandler.instance.sendEvent(AdEvent(id: id, name: message)) 76 | } 77 | } 78 | 79 | // 开屏广告加载完成 80 | func splashAdLoadSuccess(_ splashAd: BUSplashAd) { 81 | sendEvent("onSplashAdLoadSuccess") 82 | splashAd.showSplashView(inRootViewController: UIApplication.shared.keyWindow!.rootViewController!) 83 | } 84 | 85 | // 开屏广告加载失败 86 | func splashAdLoadFail(_ splashAd: BUSplashAd, error: BUAdError?) { 87 | sendEvent("onSplashAdLoadFail") 88 | splashEnd(false) 89 | } 90 | 91 | 92 | func splashAdRenderSuccess(_ splashAd: BUSplashAd) { 93 | sendEvent("splashAdRenderSuccess") 94 | } 95 | 96 | func splashAdRenderFail(_ splashAd: BUSplashAd, error: BUAdError?) { 97 | sendEvent("onSplashRenderFail") 98 | splashEnd(false) 99 | } 100 | 101 | func splashAdWillShow(_ splashAd: BUSplashAd) { 102 | sendEvent("onAdShow") 103 | 104 | GCDTool.gcdCancel(closeAdTimer) 105 | // 6s后自动跳过广告 106 | skipAdTimer = GCDTool.gcdDelay(6) { 107 | self.splashEnd(true) 108 | } 109 | } 110 | 111 | func splashAdDidShow(_ splashAd: BUSplashAd) { 112 | // sendEvent("onAdShow") 113 | } 114 | 115 | func splashAdViewControllerDidClose(_ splashAd: BUSplashAd) { 116 | } 117 | 118 | func splashVideoAdDidPlayFinish(_ splashAd: BUSplashAd, didFailWithError error: Error?) { 119 | 120 | } 121 | 122 | func splashAdDidClick(_ splashAd: BUSplashAd) { 123 | sendEvent("onAdClicked") 124 | } 125 | 126 | func splashAdDidClose(_ splashAd: BUSplashAd, closeType: BUSplashAdCloseType) { 127 | sendEvent("onSplashAdClose") 128 | splashEnd(true) 129 | } 130 | 131 | func splashDidCloseOtherController(_ splashAd: BUSplashAd, interactionType: BUInteractionType) { 132 | 133 | } 134 | 135 | // 广告结束 136 | func splashEnd(_ res: Bool) { 137 | GCDTool.gcdCancel(closeAdTimer) 138 | GCDTool.gcdCancel(skipAdTimer) 139 | 140 | if (!ended) { 141 | ended = true 142 | sendEvent("onAdEnd") 143 | result(res) 144 | splashAd?.mediation?.destoryAd() 145 | } 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /ios/flutter_gromore.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint flutter_gromore.podspec` to validate before publishing. 4 | # 5 | Pod::Spec.new do |s| 6 | s.name = 'flutter_gromore' 7 | s.version = '0.0.1' 8 | s.summary = '穿山甲Gromore插件' 9 | s.description = <<-DESC 10 | 穿山甲Gromore插件 11 | DESC 12 | s.homepage = 'http://example.com' 13 | s.license = { :file => '../LICENSE' } 14 | s.author = { 'Your Company' => 'email@example.com' } 15 | s.source = { :path => '.' } 16 | s.source_files = 'Classes/**/*' 17 | s.dependency 'Flutter' 18 | s.platform = :ios, '8.0' 19 | 20 | s.dependency 'Ads-Fusion-CN-Beta', '6.0.0.5' 21 | s.subspec 'BUAdSDK' do |cs| 22 | cs.dependency 'Ads-Fusion-CN-Beta/BUAdSDK', '6.0.0.5' 23 | end 24 | s.subspec 'CSJMediation' do |cs| 25 | cs.dependency 'Ads-Fusion-CN-Beta/CSJMediation', '6.0.0.5' 26 | end 27 | s.static_framework = true 28 | # Flutter.framework does not contain a i386 slice. 29 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } 30 | s.swift_version = '5.0' 31 | end 32 | -------------------------------------------------------------------------------- /lib/callback/gromore_banner_callback.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_gromore/callback/gromore_base_callback.dart'; 2 | import 'package:flutter_gromore/types.dart'; 3 | 4 | /// banner广告回调 5 | class GromoreBannerCallback extends GromoreBaseAdCallback { 6 | /// banner广告点击 7 | final GromoreVoidCallback? onAdClick; 8 | 9 | /// banner广告展示,仅Android可用 10 | final GromoreVoidCallback? onAdShow; 11 | 12 | /// 模板渲染失败 13 | final GromoreVoidCallback? onRenderFail; 14 | 15 | /// 模板渲染成功 16 | final GromoreVoidCallback? onRenderSuccess; 17 | 18 | /// 用户选择不喜欢原因 19 | final GromoreVoidCallback? onSelected; 20 | 21 | /// 进程被终止,仅iOS可用 22 | final GromoreVoidCallback? onAdTerminate; 23 | 24 | /// 加载失败 25 | final GromoreVoidCallback? onLoadError; 26 | 27 | GromoreBannerCallback({ 28 | this.onAdClick, 29 | this.onAdShow, 30 | this.onRenderFail, 31 | this.onRenderSuccess, 32 | this.onSelected, 33 | this.onAdTerminate, 34 | this.onLoadError, 35 | }); 36 | 37 | /// 执行回调 38 | @override 39 | void exec(String callbackName, [dynamic arguments]) { 40 | if (callbackName == "onAdClick") { 41 | onAdClick?.call(); 42 | } else if (callbackName == "onAdShow") { 43 | onAdShow?.call(); 44 | } else if (callbackName == "onRenderFail") { 45 | onRenderFail?.call(); 46 | } else if (callbackName == "onRenderSuccess") { 47 | onRenderSuccess?.call(); 48 | } else if (callbackName == "onSelected") { 49 | onSelected?.call(); 50 | } else if (callbackName == "onAdTerminate") { 51 | onAdTerminate?.call(); 52 | } else if (callbackName == "onLoadError") { 53 | onLoadError?.call(); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/callback/gromore_base_callback.dart: -------------------------------------------------------------------------------- 1 | /// 事件回调基类 2 | abstract class GromoreBaseAdCallback { 3 | /// 针对不同回调事件的处理 4 | void exec(String callbackName, [dynamic arguments]); 5 | } 6 | -------------------------------------------------------------------------------- /lib/callback/gromore_feed_callback.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_gromore/callback/gromore_base_callback.dart'; 2 | import 'package:flutter_gromore/types.dart'; 3 | 4 | /// 信息流广告回调 5 | class GromoreFeedCallback extends GromoreBaseAdCallback { 6 | /// 信息流广告点击 7 | final GromoreVoidCallback? onAdClick; 8 | 9 | /// 信息流广告展示 10 | final GromoreVoidCallback? onAdShow; 11 | 12 | /// 模板渲染失败 13 | final GromoreVoidCallback? onRenderFail; 14 | 15 | /// 模板渲染成功 16 | final GromoreFeedRenderCallback? onRenderSuccess; 17 | 18 | /// 用户选择不喜欢原因 19 | final GromoreVoidCallback? onSelected; 20 | 21 | /// 取消选择 22 | final GromoreVoidCallback? onCancel; 23 | 24 | /// 拒绝弹框显示 25 | final GromoreVoidCallback? onShow; 26 | 27 | /// 进程被终止 28 | final GromoreVoidCallback? onAdTerminate; 29 | 30 | GromoreFeedCallback({ 31 | this.onAdClick, 32 | this.onAdShow, 33 | this.onRenderFail, 34 | this.onRenderSuccess, 35 | this.onSelected, 36 | this.onCancel, 37 | this.onShow, 38 | this.onAdTerminate, 39 | }); 40 | 41 | /// 执行回调 42 | @override 43 | void exec(String callbackName, [dynamic arguments]) { 44 | if (callbackName == "onAdClick" && onAdClick != null) { 45 | onAdClick!(); 46 | } else if (callbackName == "onAdShow" && onAdShow != null) { 47 | onAdShow!(); 48 | } else if (callbackName == "onRenderFail" && onRenderFail != null) { 49 | onRenderFail!(); 50 | } else if (callbackName == "onRenderSuccess" && onRenderSuccess != null) { 51 | onRenderSuccess!(arguments["height"]); 52 | } else if (callbackName == "onSelected" && onSelected != null) { 53 | onSelected!(); 54 | } else if (callbackName == "onCancel" && onCancel != null) { 55 | onCancel!(); 56 | } else if (callbackName == "onShow" && onShow != null) { 57 | onShow!(); 58 | } else if (callbackName == "onAdTerminate" && onAdTerminate != null) { 59 | onAdTerminate!(); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/callback/gromore_interstitial_callback.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_gromore/callback/gromore_base_callback.dart'; 2 | import 'package:flutter_gromore/types.dart'; 3 | 4 | class GromoreInterstitialCallback extends GromoreBaseAdCallback { 5 | /// 广告展示 6 | final GromoreVoidCallback? onInterstitialShow; 7 | 8 | /// 展示失败 9 | final GromoreVoidCallback? onInterstitialShowFail; 10 | 11 | /// 广告被点击 12 | final GromoreVoidCallback? onInterstitialAdClick; 13 | 14 | /// 广告关闭 15 | final GromoreVoidCallback? onInterstitialClosed; 16 | 17 | GromoreInterstitialCallback({ 18 | this.onInterstitialShow, 19 | this.onInterstitialShowFail, 20 | this.onInterstitialAdClick, 21 | this.onInterstitialClosed, 22 | }); 23 | 24 | @override 25 | void exec(String callbackName, [arguments]) { 26 | if (callbackName == "onInterstitialShow" && onInterstitialShow != null) { 27 | onInterstitialShow!(); 28 | } else if (callbackName == "onInterstitialShowFail" && 29 | onInterstitialShowFail != null) { 30 | onInterstitialShowFail!(); 31 | } else if (callbackName == "onInterstitialAdClick" && 32 | onInterstitialAdClick != null) { 33 | onInterstitialAdClick!(); 34 | } else if (callbackName == "onInterstitialClosed" && 35 | onInterstitialClosed != null) { 36 | onInterstitialClosed!(); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/callback/gromore_method_channel_handler.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | import 'package:flutter_gromore/callback/gromore_base_callback.dart'; 3 | 4 | /// 处理Dart端接收到的广告事件 5 | /// T 继承自事件回调基类 6 | class GromoreMethodChannelHandler { 7 | final MethodChannel _channel; 8 | final T _callback; 9 | 10 | GromoreMethodChannelHandler(String channelName, this._callback) 11 | : _channel = MethodChannel(channelName) { 12 | // 注册事件回调 13 | _channel.setMethodCallHandler(_onMethodCall); 14 | print("====== GromoreMethodChannelHandler register $channelName ====="); 15 | } 16 | 17 | GromoreMethodChannelHandler.register(String channelName, T callback) 18 | : this(channelName, callback); 19 | 20 | Future _onMethodCall(MethodCall call) async { 21 | _callback.exec(call.method, call.arguments); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/callback/gromore_reward_callback.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_gromore/callback/gromore_base_callback.dart'; 2 | import 'package:flutter_gromore/types.dart'; 3 | 4 | class GromoreRewardCallback extends GromoreBaseAdCallback { 5 | /// 广告的展示回调 6 | final GromoreVoidCallback? onAdShow; 7 | 8 | /// 广告的下载bar点击回调,非所有广告商的广告都会触发 9 | final GromoreVoidCallback? onAdVideoBarClick; 10 | 11 | /// 广告关闭的回调 12 | final GromoreVoidCallback? onAdClose; 13 | 14 | /// 视频播放完毕的回调,非所有广告商的广告都会触发 15 | final GromoreVoidCallback? onVideoComplete; 16 | 17 | /// 视频播放失败的回调 18 | final GromoreVoidCallback? onVideoError; 19 | 20 | /// 激励视频播放完毕,验证是否有效发放奖励的回调 21 | final void Function(bool verified)? onRewardVerify; 22 | 23 | /// 跳过视频播放 24 | final GromoreVoidCallback? onSkippedVideo; 25 | 26 | GromoreRewardCallback({ 27 | this.onAdShow, 28 | this.onAdVideoBarClick, 29 | this.onAdClose, 30 | this.onVideoComplete, 31 | this.onVideoError, 32 | this.onRewardVerify, 33 | this.onSkippedVideo, 34 | }); 35 | 36 | @override 37 | void exec(String callbackName, [arguments]) { 38 | if (callbackName == "onAdShow") { 39 | onAdShow?.call(); 40 | } else if (callbackName == "onAdVideoBarClick") { 41 | onAdVideoBarClick?.call(); 42 | } else if (callbackName == "onAdClose") { 43 | onAdClose?.call(); 44 | } else if (callbackName == "onVideoComplete") { 45 | onVideoComplete?.call(); 46 | } else if (callbackName == "onVideoError") { 47 | onVideoError?.call(); 48 | } else if (callbackName == "onRewardVerify") { 49 | onRewardVerify?.call(arguments["verify"]); 50 | } else if (callbackName == "onSkippedVideo") { 51 | onSkippedVideo?.call(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/callback/gromore_splash_callback.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_gromore/callback/gromore_base_callback.dart'; 2 | import 'package:flutter_gromore/types.dart'; 3 | 4 | /// 开屏广告回调 5 | class GromoreSplashCallback extends GromoreBaseAdCallback { 6 | /// 广告被点击 7 | final GromoreVoidCallback? onAdClicked; 8 | 9 | /// 展示成功 10 | final GromoreVoidCallback? onAdShow; 11 | 12 | /// 加载失败 13 | final GromoreVoidCallback? onSplashAdLoadFail; 14 | 15 | /// 加载成功 16 | final GromoreVoidCallback? onSplashAdLoadSuccess; 17 | 18 | /// 渲染成功 19 | final GromoreVoidCallback? onSplashRenderSuccess; 20 | 21 | /// 渲染失败 22 | final GromoreVoidCallback? onSplashRenderFail; 23 | 24 | /// 关闭 25 | final GromoreVoidCallback? onSplashAdClose; 26 | 27 | /// 开屏广告结束,这个时候会销毁广告(点击跳过、倒计时结束或渲染错误等 理应隐藏广告 的情况都会触发此回调,建议统一在此回调处理路由跳转等逻辑) 28 | final GromoreVoidCallback? onAdEnd; 29 | 30 | /// 触发开屏广告自动关闭(由于存在异常场景,导致广告无法正常展示,但无相关回调) 31 | final GromoreVoidCallback? onAutoClose; 32 | 33 | /// 触发开屏广告自动跳过(由于存在部分场景,导致广告无法跳过) 34 | final GromoreVoidCallback? onAutoSkip; 35 | 36 | GromoreSplashCallback( 37 | {this.onAdClicked, 38 | this.onAdShow, 39 | this.onSplashAdLoadFail, 40 | this.onSplashAdLoadSuccess, 41 | this.onSplashRenderSuccess, 42 | this.onSplashRenderFail, 43 | this.onSplashAdClose, 44 | this.onAdEnd, 45 | this.onAutoClose, 46 | this.onAutoSkip}) 47 | : super(); 48 | 49 | /// 执行回调 50 | @override 51 | void exec(String callbackName, [dynamic arguments]) { 52 | if (callbackName == "onAdClicked") { 53 | onAdClicked?.call(); 54 | } else if (callbackName == "onAdShow") { 55 | onAdShow?.call(); 56 | } else if (callbackName == "onSplashAdLoadFail") { 57 | onSplashAdLoadFail?.call(); 58 | } else if (callbackName == "onSplashAdLoadSuccess") { 59 | onSplashAdLoadSuccess?.call(); 60 | } else if (callbackName == "onSplashRenderSuccess") { 61 | onSplashAdLoadFail?.call(); 62 | } else if (callbackName == "onSplashRenderFail") { 63 | onSplashAdLoadSuccess?.call(); 64 | } else if (callbackName == "onAdEnd") { 65 | onAdEnd?.call(); 66 | } else if (callbackName == "onAutoClose") { 67 | onAutoClose?.call(); 68 | } else if (callbackName == "onAutoSkip") { 69 | onAutoSkip?.call(); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lib/config/gromore_banner_config.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_gromore/config/gromore_base_config.dart'; 2 | 3 | class GromoreBannerConfig extends GromoreBaseAdConfig { 4 | /// 广告id 5 | final String adUnitId; 6 | 7 | /// 请求数量,默认为3 8 | final int? count; 9 | 10 | /// 宽度,默认宽度占满 11 | final int? width; 12 | 13 | /// 高度,默认为0,0为高度选择自适应参数 14 | final int? height; 15 | 16 | /// 是否使用SurfaceView,默认为true 17 | final bool? useSurfaceView; 18 | 19 | GromoreBannerConfig( 20 | {required this.adUnitId, 21 | this.count, 22 | this.width, 23 | this.height, 24 | this.useSurfaceView = true}); 25 | 26 | @override 27 | Map toJson() { 28 | Map result = { 29 | "adUnitId": adUnitId, 30 | "count": count, 31 | "width": width, 32 | "height": height, 33 | "useSurfaceView": useSurfaceView 34 | }; 35 | 36 | result.removeWhere((key, value) => value == null); 37 | 38 | return result; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/config/gromore_base_config.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | 3 | abstract class GromoreBaseAdConfig { 4 | /// 唯一标识 5 | String? id; 6 | 7 | /// 转换为Map 8 | Map toJson(); 9 | 10 | /// 生成唯一id 11 | generateId() { 12 | id = UniqueKey().hashCode.toString(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/config/gromore_feed_config.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_gromore/config/gromore_base_config.dart'; 2 | 3 | class GromoreFeedConfig extends GromoreBaseAdConfig { 4 | /// 广告id 5 | final String adUnitId; 6 | 7 | /// 请求数量,默认为3 8 | final int? count; 9 | 10 | /// 宽度,默认宽度占满 11 | final int? width; 12 | 13 | /// 高度,默认为0,0为高度选择自适应参数 14 | final int? height; 15 | 16 | /// 是否使用SurfaceView,默认为true 17 | final bool? useSurfaceView; 18 | 19 | GromoreFeedConfig( 20 | {required this.adUnitId, 21 | this.count, 22 | this.width, 23 | this.height, 24 | this.useSurfaceView = true}); 25 | 26 | @override 27 | Map toJson() { 28 | Map result = { 29 | "adUnitId": adUnitId, 30 | "count": count, 31 | "width": width, 32 | "height": height, 33 | "useSurfaceView": useSurfaceView 34 | }; 35 | 36 | result.removeWhere((key, value) => value == null); 37 | 38 | return result; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/config/gromore_interstitial_config.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_gromore/config/gromore_base_config.dart'; 2 | import 'package:flutter_gromore/utils/gromore_ad_size.dart'; 3 | 4 | /// 插屏广告配置 5 | class GromoreInterstitialConfig extends GromoreBaseAdConfig { 6 | /// 广告id 7 | final String adUnitId; 8 | 9 | /// 广告尺寸 10 | /// 配置将不会生效,已过时 11 | final GromoreAdSize? size; 12 | 13 | /// 设置横竖,仅Android可用。竖屏为1,横屏为2。默认竖屏 14 | final int? orientation; 15 | 16 | /// 是否静音,默认为true 17 | final bool? muted; 18 | 19 | /// 是否使用SurfaceView,默认为true 20 | final bool? useSurfaceView; 21 | 22 | GromoreInterstitialConfig( 23 | {required this.adUnitId, 24 | this.size, 25 | this.orientation, 26 | this.muted, 27 | this.useSurfaceView = true}); 28 | 29 | @override 30 | Map toJson() { 31 | return { 32 | "id": id, 33 | "adUnitId": adUnitId, 34 | "muted": muted, 35 | "orientation": orientation, 36 | "useSurfaceView": useSurfaceView 37 | }; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/config/gromore_reward_config.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_gromore/config/gromore_base_config.dart'; 2 | 3 | /// 激励广告配置 4 | class GromoreRewardConfig extends GromoreBaseAdConfig { 5 | /// 广告ID 6 | final String adUnitId; 7 | 8 | /// 播放方向。竖屏:1,横屏:2。默认为竖屏。仅Android端有效 9 | final int? orientation; 10 | 11 | /// 是否静音,默认为true 12 | final bool? muted; 13 | 14 | /// 音量,默认为0 15 | final double? volume; 16 | 17 | /// 是否使用SurfaceView,默认为true 18 | final bool? useSurfaceView; 19 | 20 | GromoreRewardConfig( 21 | {required this.adUnitId, 22 | this.orientation, 23 | this.muted, 24 | this.volume, 25 | this.useSurfaceView = true}); 26 | 27 | @override 28 | Map toJson() { 29 | Map result = { 30 | "adUnitId": adUnitId, 31 | "orientation": orientation, 32 | "muted": muted, 33 | "volume": volume, 34 | "useSurfaceView": useSurfaceView 35 | }; 36 | 37 | result.removeWhere((key, value) => value == null); 38 | 39 | return result; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/config/gromore_splash_config.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_gromore/config/gromore_base_config.dart'; 2 | 3 | /// 开屏广告配置 4 | class GromoreSplashConfig extends GromoreBaseAdConfig { 5 | /// 广告id 6 | final String adUnitId; 7 | 8 | /// 广告宽度(自定义渲染可用) 9 | /// 将不再维护 10 | final double? width; 11 | 12 | /// 广告高度(自定义渲染可用) 13 | /// 将不再维护 14 | final double? height; 15 | 16 | /// 如果传入了logo则会在底部显示logo,logo放在android/app/src/main/res/mipmap下,值不需要文件后缀(非自定义渲染可用) 17 | final String? logo; 18 | 19 | /// 静音,默认为true 20 | final bool? muted; 21 | 22 | /// 预加载,默认为true 23 | final bool? preload; 24 | 25 | /// 声音配置,与muted配合使用 26 | final double? volume; 27 | 28 | /// 开屏摇一摇开关,默认为true 29 | final bool? splashShakeButton; 30 | 31 | /// bidding类型广告,竞价成功或者失败后是否通知对应的adn,默认为false 32 | final bool? bidNotify; 33 | 34 | /// 超时时间 35 | final int? timeout; 36 | 37 | /// 是否使用SurfaceView,默认为true 38 | final bool? useSurfaceView; 39 | 40 | GromoreSplashConfig({ 41 | required this.adUnitId, 42 | this.width, 43 | this.height, 44 | this.logo, 45 | this.muted, 46 | this.preload, 47 | this.volume, 48 | this.splashShakeButton, 49 | this.bidNotify, 50 | this.timeout, 51 | this.useSurfaceView = true, 52 | }); 53 | 54 | @override 55 | Map toJson() { 56 | Map result = { 57 | "id": id, 58 | "width": width, 59 | "height": height, 60 | "adUnitId": adUnitId, 61 | "logo": logo, 62 | "muted": muted, 63 | "preload": preload, 64 | "volume": volume, 65 | "splashShakeButton": splashShakeButton, 66 | "bidNotify": bidNotify, 67 | "timeout": timeout, 68 | }; 69 | result.removeWhere((key, value) => value == null); 70 | return result; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lib/constants/gromore_constans.dart: -------------------------------------------------------------------------------- 1 | /// 相关常量 2 | class FlutterGromoreConstants { 3 | /// channel 4 | static const methodChannelName = "flutter_gromore"; 5 | static const eventChannelName = "flutter_gromore_event"; 6 | 7 | /// 信息流注册名 8 | static const feedViewTypeId = "flutter_gromore_feed"; 9 | 10 | /// 插屏广告注册名 11 | static const interstitialTypeId = "flutter_gromore_interstitial"; 12 | 13 | /// 开屏广告注册名 14 | static const splashTypeId = "flutter_gromore_splash"; 15 | 16 | /// 开屏广告注册名 17 | static const rewardTypeId = "flutter_gromore_reward"; 18 | 19 | /// banner注册名 20 | static const bannerTypeId = "flutter_gromore_banner"; 21 | } 22 | -------------------------------------------------------------------------------- /lib/types.dart: -------------------------------------------------------------------------------- 1 | /// 无返回值 2 | typedef GromoreVoidCallback = void Function(); 3 | 4 | typedef GromoreFeedRenderCallback = void Function(double height); 5 | -------------------------------------------------------------------------------- /lib/utils/gromore_ad_size.dart: -------------------------------------------------------------------------------- 1 | /// 广告尺寸 2 | class GromoreAdSize { 3 | /// 宽 4 | final double? width; 5 | 6 | /// 高 7 | final double? height; 8 | 9 | GromoreAdSize({this.width, this.height}); 10 | 11 | /// adWidth:广告宽度 12 | /// 宽高比 13 | GromoreAdSize.withPercent(double adWidth, double ratio) 14 | : width = adWidth, 15 | height = adWidth / ratio; 16 | } 17 | -------------------------------------------------------------------------------- /lib/view/gromore_banner_view.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/foundation.dart'; 4 | import 'package:flutter/gestures.dart'; 5 | import 'package:flutter/rendering.dart'; 6 | import 'package:flutter/services.dart'; 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_gromore/callback/gromore_banner_callback.dart'; 9 | import 'package:flutter_gromore/callback/gromore_method_channel_handler.dart'; 10 | import 'package:flutter_gromore/constants/gromore_constans.dart'; 11 | 12 | import 'package:flutter_gromore/flutter_gromore.dart'; 13 | import 'package:visibility_detector/visibility_detector.dart'; 14 | 15 | /// 信息流广告组件 16 | class GromoreBannerView extends StatefulWidget { 17 | final Map creationParams; 18 | 19 | /// 回调 20 | final GromoreBannerCallback callback; 21 | 22 | const GromoreBannerView( 23 | {Key? key, required this.creationParams, required this.callback}) 24 | : super(key: key); 25 | 26 | @override 27 | State createState() => _GromoreBannerViewState(); 28 | } 29 | 30 | class _GromoreBannerViewState extends State { 31 | final UniqueKey _detectorKey = UniqueKey(); 32 | 33 | MethodChannel? _methodChannel; 34 | 35 | @override 36 | void initState() { 37 | VisibilityDetectorController.instance.updateInterval = 38 | const Duration(milliseconds: 100); 39 | super.initState(); 40 | } 41 | 42 | @override 43 | Widget build(BuildContext context) { 44 | if (!FlutterGromore.isInit) { 45 | print("============== 请先初始化SDK =============="); 46 | } 47 | 48 | String viewType = FlutterGromoreConstants.bannerTypeId; 49 | 50 | return Platform.isAndroid 51 | ? PlatformViewLink( 52 | viewType: viewType, 53 | surfaceFactory: 54 | (BuildContext context, PlatformViewController controller) { 55 | return AndroidViewSurface( 56 | controller: controller as AndroidViewController, 57 | gestureRecognizers: const < 58 | Factory>{}, 59 | hitTestBehavior: PlatformViewHitTestBehavior.opaque, 60 | ); 61 | }, 62 | onCreatePlatformView: (PlatformViewCreationParams params) { 63 | return PlatformViewsService.initSurfaceAndroidView( 64 | id: params.id, 65 | viewType: viewType, 66 | layoutDirection: TextDirection.ltr, 67 | creationParams: widget.creationParams, 68 | creationParamsCodec: const StandardMessageCodec(), 69 | onFocus: () { 70 | params.onFocusChanged(true); 71 | }, 72 | ) 73 | ..addOnPlatformViewCreatedListener((id) { 74 | if (!mounted) { 75 | return; 76 | } 77 | params.onPlatformViewCreated(id); 78 | 79 | // 注册事件回调 80 | GromoreMethodChannelHandler.register( 81 | "$viewType/$id", widget.callback); 82 | }) 83 | ..create(); 84 | }, 85 | ) 86 | : VisibilityDetector( 87 | key: _detectorKey, 88 | child: UiKitView( 89 | viewType: viewType, 90 | creationParams: widget.creationParams, 91 | creationParamsCodec: const StandardMessageCodec(), 92 | onPlatformViewCreated: (id) { 93 | final String channelName = "$viewType/$id"; 94 | _methodChannel = MethodChannel(channelName); 95 | // 注册事件回调 96 | GromoreMethodChannelHandler.register( 97 | channelName, widget.callback); 98 | }), 99 | onVisibilityChanged: (VisibilityInfo visibilityInfo) { 100 | if (!mounted) return; 101 | // 被遮盖了 102 | final bool isCovered = visibilityInfo.visibleFraction != 1.0; 103 | final Offset offset = (context.findRenderObject() as RenderBox) 104 | .localToGlobal(Offset.zero); 105 | _methodChannel?.invokeMethod('updateVisibleBounds', { 106 | 'isCovered': isCovered, 107 | 'x': offset.dx + visibilityInfo.visibleBounds.left, 108 | 'y': offset.dy + visibilityInfo.visibleBounds.top, 109 | 'width': visibilityInfo.visibleBounds.width, 110 | 'height': visibilityInfo.visibleBounds.height, 111 | }); 112 | }, 113 | ); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /lib/view/gromore_feed_view.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/foundation.dart'; 4 | import 'package:flutter/gestures.dart'; 5 | import 'package:flutter/rendering.dart'; 6 | import 'package:flutter/services.dart'; 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_gromore/callback/gromore_feed_callback.dart'; 9 | import 'package:flutter_gromore/callback/gromore_method_channel_handler.dart'; 10 | import 'package:flutter_gromore/constants/gromore_constans.dart'; 11 | 12 | import 'package:flutter_gromore/flutter_gromore.dart'; 13 | import 'package:visibility_detector/visibility_detector.dart'; 14 | 15 | /// 信息流广告组件 16 | class GromoreFeedView extends StatefulWidget { 17 | final Map creationParams; 18 | 19 | /// 回调 20 | final GromoreFeedCallback callback; 21 | 22 | const GromoreFeedView( 23 | {Key? key, required this.creationParams, required this.callback}) 24 | : super(key: key); 25 | 26 | @override 27 | State createState() => _GromoreFeedViewState(); 28 | } 29 | 30 | class _GromoreFeedViewState extends State { 31 | final UniqueKey _detectorKey = UniqueKey(); 32 | 33 | MethodChannel? _methodChannel; 34 | 35 | @override 36 | void initState() { 37 | VisibilityDetectorController.instance.updateInterval = 38 | const Duration(milliseconds: 100); 39 | super.initState(); 40 | } 41 | 42 | @override 43 | Widget build(BuildContext context) { 44 | if (!FlutterGromore.isInit) { 45 | print("============== 请先初始化SDK =============="); 46 | } 47 | 48 | String viewType = FlutterGromoreConstants.feedViewTypeId; 49 | 50 | return Platform.isAndroid 51 | ? PlatformViewLink( 52 | viewType: viewType, 53 | surfaceFactory: 54 | (BuildContext context, PlatformViewController controller) { 55 | return AndroidViewSurface( 56 | controller: controller as AndroidViewController, 57 | gestureRecognizers: const < 58 | Factory>{}, 59 | hitTestBehavior: PlatformViewHitTestBehavior.opaque, 60 | ); 61 | }, 62 | onCreatePlatformView: (PlatformViewCreationParams params) { 63 | return PlatformViewsService.initSurfaceAndroidView( 64 | id: params.id, 65 | viewType: viewType, 66 | layoutDirection: TextDirection.ltr, 67 | creationParams: widget.creationParams, 68 | creationParamsCodec: const StandardMessageCodec(), 69 | onFocus: () { 70 | params.onFocusChanged(true); 71 | }, 72 | ) 73 | ..addOnPlatformViewCreatedListener((id) { 74 | if (!mounted) { 75 | return; 76 | } 77 | params.onPlatformViewCreated(id); 78 | 79 | // 注册事件回调 80 | GromoreMethodChannelHandler.register( 81 | "$viewType/$id", widget.callback); 82 | }) 83 | ..create(); 84 | }, 85 | ) 86 | : VisibilityDetector( 87 | key: _detectorKey, 88 | child: UiKitView( 89 | viewType: viewType, 90 | creationParams: widget.creationParams, 91 | creationParamsCodec: const StandardMessageCodec(), 92 | onPlatformViewCreated: (id) { 93 | final String channelName = "$viewType/$id"; 94 | _methodChannel = MethodChannel(channelName); 95 | // 注册事件回调 96 | GromoreMethodChannelHandler.register( 97 | channelName, widget.callback); 98 | }), 99 | onVisibilityChanged: (VisibilityInfo visibilityInfo) { 100 | if (!mounted) return; 101 | // 被遮盖了 102 | final bool isCovered = visibilityInfo.visibleFraction != 1.0; 103 | final Offset offset = (context.findRenderObject() as RenderBox) 104 | .localToGlobal(Offset.zero); 105 | _methodChannel?.invokeMethod('updateVisibleBounds', { 106 | 'isCovered': isCovered, 107 | 'x': offset.dx + visibilityInfo.visibleBounds.left, 108 | 'y': offset.dy + visibilityInfo.visibleBounds.top, 109 | 'width': visibilityInfo.visibleBounds.width, 110 | 'height': visibilityInfo.visibleBounds.height, 111 | }); 112 | }, 113 | ); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /lib/view/gromore_splash_view.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/foundation.dart'; 4 | import 'package:flutter/gestures.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter/services.dart'; 7 | import 'package:flutter/rendering.dart'; 8 | import 'package:flutter_gromore/callback/gromore_method_channel_handler.dart'; 9 | import 'package:flutter_gromore/callback/gromore_splash_callback.dart'; 10 | import 'package:flutter_gromore/config/gromore_splash_config.dart'; 11 | import 'package:flutter_gromore/constants/gromore_constans.dart'; 12 | import 'package:flutter_gromore/flutter_gromore.dart'; 13 | 14 | /// 开屏广告组件(自定义布局渲染) 15 | class GromoreSplashView extends StatefulWidget { 16 | /// PlatformView参数 17 | final GromoreSplashConfig creationParams; 18 | 19 | /// 回调 20 | final GromoreSplashCallback? callback; 21 | 22 | const GromoreSplashView( 23 | {Key? key, required this.creationParams, this.callback}) 24 | : super(key: key); 25 | 26 | @override 27 | State createState() => _GromoreSplashViewState(); 28 | } 29 | 30 | class _GromoreSplashViewState extends State { 31 | @override 32 | Widget build(BuildContext context) { 33 | if (!FlutterGromore.isInit) { 34 | return const SizedBox( 35 | height: 200, 36 | child: Center( 37 | child: Text("请先初始化SDK"), 38 | ), 39 | ); 40 | } 41 | 42 | return Platform.isAndroid 43 | ? PlatformViewLink( 44 | viewType: FlutterGromoreConstants.splashTypeId, 45 | surfaceFactory: 46 | (BuildContext context, PlatformViewController controller) { 47 | return AndroidViewSurface( 48 | controller: controller as AndroidViewController, 49 | gestureRecognizers: const < 50 | Factory>{}, 51 | hitTestBehavior: PlatformViewHitTestBehavior.opaque, 52 | ); 53 | }, 54 | onCreatePlatformView: (PlatformViewCreationParams params) { 55 | return PlatformViewsService.initSurfaceAndroidView( 56 | id: params.id, 57 | viewType: FlutterGromoreConstants.splashTypeId, 58 | layoutDirection: TextDirection.ltr, 59 | creationParams: widget.creationParams.toJson(), 60 | creationParamsCodec: const StandardMessageCodec(), 61 | onFocus: () { 62 | params.onFocusChanged(true); 63 | }, 64 | ) 65 | ..addOnPlatformViewCreatedListener((id) { 66 | if (!mounted) { 67 | return; 68 | } 69 | params.onPlatformViewCreated(id); 70 | 71 | // 注册事件回调 72 | if (widget.callback != null) { 73 | GromoreMethodChannelHandler.register( 74 | "${FlutterGromoreConstants.splashTypeId}/$id", 75 | widget.callback!); 76 | } 77 | }) 78 | ..create(); 79 | }, 80 | ) 81 | : Container(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.flutter-io.cn" 9 | source: hosted 10 | version: "2.9.0" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.flutter-io.cn" 16 | source: hosted 17 | version: "2.1.0" 18 | characters: 19 | dependency: transitive 20 | description: 21 | name: characters 22 | url: "https://pub.flutter-io.cn" 23 | source: hosted 24 | version: "1.2.1" 25 | clock: 26 | dependency: transitive 27 | description: 28 | name: clock 29 | url: "https://pub.flutter-io.cn" 30 | source: hosted 31 | version: "1.1.1" 32 | collection: 33 | dependency: transitive 34 | description: 35 | name: collection 36 | url: "https://pub.flutter-io.cn" 37 | source: hosted 38 | version: "1.16.0" 39 | fake_async: 40 | dependency: transitive 41 | description: 42 | name: fake_async 43 | url: "https://pub.flutter-io.cn" 44 | source: hosted 45 | version: "1.3.1" 46 | flutter: 47 | dependency: "direct main" 48 | description: flutter 49 | source: sdk 50 | version: "0.0.0" 51 | flutter_lints: 52 | dependency: "direct dev" 53 | description: 54 | name: flutter_lints 55 | url: "https://pub.flutter-io.cn" 56 | source: hosted 57 | version: "1.0.4" 58 | flutter_test: 59 | dependency: "direct dev" 60 | description: flutter 61 | source: sdk 62 | version: "0.0.0" 63 | lints: 64 | dependency: transitive 65 | description: 66 | name: lints 67 | url: "https://pub.flutter-io.cn" 68 | source: hosted 69 | version: "1.0.1" 70 | matcher: 71 | dependency: transitive 72 | description: 73 | name: matcher 74 | url: "https://pub.flutter-io.cn" 75 | source: hosted 76 | version: "0.12.12" 77 | material_color_utilities: 78 | dependency: transitive 79 | description: 80 | name: material_color_utilities 81 | url: "https://pub.flutter-io.cn" 82 | source: hosted 83 | version: "0.1.5" 84 | meta: 85 | dependency: transitive 86 | description: 87 | name: meta 88 | url: "https://pub.flutter-io.cn" 89 | source: hosted 90 | version: "1.8.0" 91 | path: 92 | dependency: transitive 93 | description: 94 | name: path 95 | url: "https://pub.flutter-io.cn" 96 | source: hosted 97 | version: "1.8.2" 98 | sky_engine: 99 | dependency: transitive 100 | description: flutter 101 | source: sdk 102 | version: "0.0.99" 103 | source_span: 104 | dependency: transitive 105 | description: 106 | name: source_span 107 | url: "https://pub.flutter-io.cn" 108 | source: hosted 109 | version: "1.9.0" 110 | stack_trace: 111 | dependency: transitive 112 | description: 113 | name: stack_trace 114 | url: "https://pub.flutter-io.cn" 115 | source: hosted 116 | version: "1.10.0" 117 | stream_channel: 118 | dependency: transitive 119 | description: 120 | name: stream_channel 121 | url: "https://pub.flutter-io.cn" 122 | source: hosted 123 | version: "2.1.0" 124 | string_scanner: 125 | dependency: transitive 126 | description: 127 | name: string_scanner 128 | url: "https://pub.flutter-io.cn" 129 | source: hosted 130 | version: "1.1.1" 131 | term_glyph: 132 | dependency: transitive 133 | description: 134 | name: term_glyph 135 | url: "https://pub.flutter-io.cn" 136 | source: hosted 137 | version: "1.2.1" 138 | test_api: 139 | dependency: transitive 140 | description: 141 | name: test_api 142 | url: "https://pub.flutter-io.cn" 143 | source: hosted 144 | version: "0.4.12" 145 | vector_math: 146 | dependency: transitive 147 | description: 148 | name: vector_math 149 | url: "https://pub.flutter-io.cn" 150 | source: hosted 151 | version: "2.1.2" 152 | visibility_detector: 153 | dependency: "direct main" 154 | description: 155 | name: visibility_detector 156 | url: "https://pub.flutter-io.cn" 157 | source: hosted 158 | version: "0.4.0+2" 159 | sdks: 160 | dart: ">=2.17.0-0 <3.0.0" 161 | flutter: ">=3.1.0-0" 162 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_gromore 2 | description: 一款集成了穿山甲Gromore融合SDK的flutter插件,支持Android/iOS,多种广告类型。持续更新SDK版本 3 | version: 2.1.0 4 | homepage: https://github.com/50431040/flutter_gromore 5 | repository: https://github.com/50431040/flutter_gromore 6 | documentation: https://github.com/50431040/flutter_gromore/blob/main/README.md 7 | issue_tracker: https://github.com/50431040/flutter_gromore/issues 8 | 9 | environment: 10 | sdk: ">=2.12.0 <3.0.0" 11 | flutter: ">=1.20.0" 12 | 13 | dependencies: 14 | flutter: 15 | sdk: flutter 16 | visibility_detector: ^0.4.0+2 17 | 18 | dev_dependencies: 19 | flutter_test: 20 | sdk: flutter 21 | flutter_lints: ^1.0.0 22 | 23 | # For information on the generic Dart part of this file, see the 24 | # following page: https://dart.dev/tools/pub/pubspec 25 | 26 | # The following section is specific to Flutter. 27 | flutter: 28 | # This section identifies this Flutter project as a plugin project. 29 | # The 'pluginClass' and Android 'package' identifiers should not ordinarily 30 | # be modified. They are used by the tooling to maintain consistency when 31 | # adding or updating assets for this project. 32 | plugin: 33 | platforms: 34 | android: 35 | package: net.niuxiaoer.flutter_gromore 36 | pluginClass: FlutterGromorePlugin 37 | ios: 38 | pluginClass: FlutterGromorePlugin 39 | 40 | # To add assets to your plugin package, add an assets section, like this: 41 | # assets: 42 | # - images/a_dot_burr.jpeg 43 | # - images/a_dot_ham.jpeg 44 | # 45 | # For details regarding assets in packages, see 46 | # https://flutter.dev/assets-and-images/#from-packages 47 | # 48 | # An image asset can refer to one or more resolution-specific "variants", see 49 | # https://flutter.dev/assets-and-images/#resolution-aware. 50 | 51 | # To add custom fonts to your plugin package, add a fonts section here, 52 | # in this "flutter" section. Each entry in this list should have a 53 | # "family" key with the font family name, and a "fonts" key with a 54 | # list giving the asset and other descriptors for the font. For 55 | # example: 56 | # fonts: 57 | # - family: Schyler 58 | # fonts: 59 | # - asset: fonts/Schyler-Regular.ttf 60 | # - asset: fonts/Schyler-Italic.ttf 61 | # style: italic 62 | # - family: Trajan Pro 63 | # fonts: 64 | # - asset: fonts/TrajanPro.ttf 65 | # - asset: fonts/TrajanPro_Bold.ttf 66 | # weight: 700 67 | # 68 | # For details regarding fonts in packages, see 69 | # https://flutter.dev/custom-fonts/#from-packages 70 | -------------------------------------------------------------------------------- /screenshots/group.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/screenshots/group.jpg -------------------------------------------------------------------------------- /screenshots/ios-frameworks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/screenshots/ios-frameworks.png -------------------------------------------------------------------------------- /screenshots/pangle-xcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/screenshots/pangle-xcode.png -------------------------------------------------------------------------------- /screenshots/qrcode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/50431040/flutter_gromore/2498e4e42798cb37b7035341047de69b03ea7c8a/screenshots/qrcode.jpg -------------------------------------------------------------------------------- /test/flutter_gromore_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:flutter_test/flutter_test.dart'; 4 | import 'package:flutter_gromore/flutter_gromore.dart'; 5 | 6 | void main() { 7 | const MethodChannel channel = MethodChannel('flutter_gromore'); 8 | 9 | TestWidgetsFlutterBinding.ensureInitialized(); 10 | 11 | setUp(() { 12 | channel.setMockMethodCallHandler((MethodCall methodCall) async { 13 | return '42'; 14 | }); 15 | }); 16 | 17 | tearDown(() { 18 | channel.setMockMethodCallHandler(null); 19 | }); 20 | 21 | test('getPlatformVersion', () async {}); 22 | } 23 | --------------------------------------------------------------------------------