├── .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 |
--------------------------------------------------------------------------------