├── .gitattributes ├── .gitignore ├── .metadata ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── proguard-rules.pro ├── settings.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── kotlin │ └── com │ │ └── gstory │ │ └── flutter_tencentad │ │ ├── DownloadApkConfirmDialog.java │ │ ├── DownloadConfirmHelper.java │ │ ├── FlutterTencentAdConfig.kt │ │ ├── FlutterTencentAdEventPlugin.kt │ │ ├── FlutterTencentAdViewPlugin.kt │ │ ├── FlutterTencentadPlugin.kt │ │ ├── LogUtil.kt │ │ ├── UIUtils.kt │ │ ├── bannerad │ │ ├── BannerAdView.kt │ │ └── BannerAdViewFactory.kt │ │ ├── expressad │ │ ├── NativeExpressAdView.kt │ │ └── NativeExpressAdViewFactory.kt │ │ ├── interstitialad │ │ └── InterstitialAd.kt │ │ ├── rewardvideoad │ │ └── RewardVideoAd.kt │ │ └── splashad │ │ ├── SplashAdView.kt │ │ └── SplashAdViewFactory.kt │ └── res │ ├── anim │ ├── download_confirm_dialog_slide_right_in.xml │ └── download_confirm_dialog_slide_up.xml │ ├── drawable │ ├── download_confirm_background_confirm.xml │ ├── download_confirm_background_landscape.xml │ ├── download_confirm_background_portrait.xml │ └── ic_download_confirm_close.xml │ ├── layout │ └── download_confirm_dialog.xml │ └── values │ └── styles.xml ├── error.md ├── example ├── .gitignore ├── .metadata ├── README.md ├── analysis_options.yaml ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── gstory │ │ │ │ │ └── flutter_tencentad_example │ │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.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 │ │ │ └── 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.h │ │ ├── AppDelegate.m │ │ ├── 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 │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── main.m ├── lib │ ├── banner_page.dart │ ├── express_page.dart │ ├── main.dart │ └── splash_page.dart ├── pubspec.lock ├── pubspec.yaml └── test │ └── widget_test.dart ├── images ├── tencentad.gif └── weixin.jpg ├── ios ├── .gitignore ├── Assets │ └── .gitkeep ├── Classes │ ├── FlutterTencentadPlugin.h │ ├── FlutterTencentadPlugin.m │ ├── banner │ │ ├── BannerAd.h │ │ └── BannerAd.m │ ├── event │ │ ├── FlutterTencentAdEvent.h │ │ └── FlutterTencentAdEvent.m │ ├── insert │ │ ├── InsertAd.h │ │ └── InsertAd.m │ ├── native │ │ ├── NativeAd.h │ │ └── NativeAd.m │ ├── reward │ │ ├── RewardAd.h │ │ └── RewardAd.m │ ├── splash │ │ ├── SplashAd.h │ │ └── SplashAd.m │ └── utils │ │ ├── TLogUtil.h │ │ ├── TLogUtil.m │ │ ├── TUIViewController+getCurrentVC.h │ │ └── TUIViewController+getCurrentVC.m └── flutter_tencentad.podspec ├── lib ├── banner │ └── banner_ad_view.dart ├── express │ └── express_ad_view.dart ├── flutter_tencentad.dart ├── flutter_tencentad_bidding_controller.dart ├── flutter_tencentad_callback.dart ├── flutter_tencentad_code.dart.dart ├── flutter_tencentad_stream.dart └── splash │ └── splash_ad_view.dart ├── pubspec.lock ├── pubspec.yaml └── test └── flutter_tencentad_test.dart /.gitattributes: -------------------------------------------------------------------------------- 1 | *.kt linguist-language=dart -------------------------------------------------------------------------------- /.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 | # Visual Studio Code related 19 | .vscode/ 20 | 21 | # Flutter/Dart/Pub related 22 | **/doc/api/ 23 | .dart_tool/ 24 | .flutter-plugins 25 | .flutter-plugins-dependencies 26 | .packages 27 | .pub-cache/ 28 | .pub/ 29 | /build/ 30 | 31 | # Android related 32 | **/android/**/gradle-wrapper.jar 33 | **/android/.gradle 34 | **/android/captures/ 35 | **/android/gradlew 36 | **/android/gradlew.bat 37 | **/android/local.properties 38 | **/android/**/GeneratedPluginRegistrant.java 39 | **/android/key/ 40 | 41 | # iOS/XCode related 42 | **/ios/**/*.mode1v3 43 | **/ios/**/*.mode2v3 44 | **/ios/**/*.moved-aside 45 | **/ios/**/*.pbxuser 46 | **/ios/**/*.perspectivev3 47 | **/ios/**/*sync/ 48 | **/ios/**/.sconsign.dblite 49 | **/ios/**/.tags* 50 | **/ios/**/.vagrant/ 51 | **/ios/**/DerivedData/ 52 | **/ios/**/Icon? 53 | **/ios/**/Pods/ 54 | **/ios/**/.symlinks/ 55 | **/ios/**/profile 56 | **/ios/**/xcuserdata 57 | **/ios/.generated/ 58 | **/ios/Flutter/App.framework 59 | **/ios/Flutter/Flutter.framework 60 | **/ios/Flutter/Generated.xcconfig 61 | **/ios/Flutter/app.flx 62 | **/ios/Flutter/app.zip 63 | **/ios/Flutter/flutter_assets/ 64 | **/ios/ServiceDefinitions.json 65 | **/ios/Runner/GeneratedPluginRegistrant.* 66 | 67 | # Exceptions to above rules. 68 | !**/ios/**/default.mode1v3 69 | !**/ios/**/default.mode2v3 70 | !**/ios/**/default.pbxuser 71 | !**/ios/**/default.perspectivev3 72 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages -------------------------------------------------------------------------------- /.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: f4abaa0735eba4dfd8f33f73363911d63931fe03 8 | channel: stable 9 | 10 | project_type: plugin 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.2.35 2 | * android sdk升级4.640.1510 3 | * ios sdk升级4.15.40 4 | * 优化ios激励广告监听 5 | 6 | ## 1.2.34 7 | * android sdk升级4.630.1500 8 | * ios sdk升级4.15.30 9 | 10 | ## 1.2.33 11 | * ios sdk升级4.15.22 12 | 13 | ## 1.2.32 14 | * ios sdk回退4.15.10 15 | 16 | ## 1.2.31 17 | * android sdk升级4.620.1490 18 | * ios sdk升级4.15.21 19 | 20 | ## 1.2.30 21 | * 修复ios sdk中包路径问题 22 | 23 | ## 1.2.29 24 | * android sdk升级4.611.1481 25 | * ios sdk升级4.15.20 26 | * android隐私权限修改 27 | 28 | ## 1.2.28 29 | * android高版本兼容 30 | 31 | ## 1.2.27 32 | * android升级4.610.1480 33 | 34 | 35 | ## 1.2.26 36 | * 新增安卓隐私合规,是否开启收集应用安装状态(感谢@[langyuxiansheng](https://github.com/langyuxiansheng) pr) 37 | 38 | ## 1.2.25 39 | * android增加namespace 40 | 41 | 42 | ## 1.2.24 43 | * android更新4.603.1473 44 | * ios更新4.15.10 45 | 46 | ## 1.2.23 47 | * android更新4.600.1470 48 | * ios更新4.15.00 49 | * 初始化新增android隐私设置androidPrivacy 50 | 51 | ## 1.2.22 52 | * android更新4.591.1461 53 | * ios更新4.14.90 54 | 55 | ## 1.2.21 56 | * android升级4.562.1432 57 | * ios升级4.14.63 58 | 59 | ## 1.2.19 60 | * android升级4.542.1412 61 | * ios升级4.14.45 62 | 63 | ## 1.2.19 64 | * android升级4.541.1411 65 | * ios升级4.14.42 66 | * loadRewardVideoAd激励广告新增videoMuted控制视频是否静音播放 67 | 68 | ## 1.2.18 69 | * android升级4.540.1410 70 | 71 | ## 1.2.17 72 | * android升级4.531.1401 73 | * ios升级4.14.32 74 | 75 | ## 1.2.16 76 | * android kt升级1.6.10 gradle插件7.1.2 77 | 78 | ## 1.2.15 79 | * android升级4.530.1400 80 | * ios升级4.14.30 81 | 82 | ## 1.2.14 83 | * android升级4.510.1380 84 | * ios升级4.14.10 85 | 86 | ## 1.2.13 87 | * 修复ios banner广告无法加载 88 | 89 | ## 1.2.12 90 | * android 升级4.500.1370 91 | * iOS 升级4.14.01 92 | 93 | * ## 1.2.11 94 | * android升级4.492.1362 兼容13 95 | 96 | ## 1.2.10 97 | * fix bug 98 | 99 | ## 1.2.8 100 | * android升级4.490.1361 101 | * fix bug 102 | 103 | ## 1.2.7 104 | * android升级4.490.1360 105 | * ios升级4.13.90 106 | 107 | ## 1.2.6 108 | * fix bug 109 | * ios升级4.13.83 110 | 111 | ## 1.2.5 112 | * fix bug 113 | 114 | 115 | ## 1.2.4 116 | * 支持bidding模式 117 | 118 | 119 | ## 1.2.3 120 | * ios错误日志优化 121 | 122 | ## 1.2.2 123 | * android升级[4.482.1352](https://developers.adnet.qq.com/doc/android/union/union_version) 124 | * ios升级[4.13.81](https://developers.adnet.qq.com/doc/ios/union/union_version) 125 | * 126 | ## 1.2.1 127 | * android升级[4.13.65](https://developers.adnet.qq.com/doc/android/union/union_version) 128 | * ios升级[4.13.65](https://developers.adnet.qq.com/doc/ios/union/union_version) 129 | 130 | ## 1.2.0 131 | * 兼容Flutter3.0 132 | * ios升级4.13.65 133 | 134 | ## 1.1.7 135 | * 修复与flutter_pangrowth文件冲突问题 136 | 137 | ## 1.1.6 138 | * 降低andorid编译版本 139 | 140 | ## 1.1.5 141 | *Android sdk升级4.460.1330 142 | *iOS sdk升级4.13.62 143 | 144 | ## 1.1.4 145 | * android sdk升级4.441.1311聚合 146 | * ios sdk升级4.13.41聚合 147 | 148 | ## 1.1.3 149 | * 优化插屏激励广告 150 | 151 | ## 1.1.2 152 | * 修复参数异常 153 | 154 | ## 1.1.1 155 | 156 | * android sdk升级4.440.1310 157 | * ios sdk升级4.13.40 158 | * FlutterTencentad.register新增参数 159 | ``` 160 | channelId 渠道id [FlutterTencentadChannel] 161 | personalized 是否开启个性化广告 [FlutterTencentadPersonalized] 162 | ``` 163 | * FlutterTencentadInteractionCallBack插屏广告回调新增激励奖励凭证id回调 164 | ```dart 165 | FlutterTencentadInteractionCallBack( 166 | onVerify: (transId,rewardName,rewardAmount){ 167 | print("广告奖励凭证id $transId"); 168 | } 169 | ), 170 | ``` 171 | 172 | ## 1.1.0 173 | 174 | * 1、ios部分使用OC重写 175 | * 2、android sdk升级4.431.1301 176 | * 3、ios sdk升级4.13.32 177 | 178 | ## 1.0.5 179 | 180 | * 1、升级sdk版本 181 | 182 | 183 | ## 1.0.4 184 | 185 | * 1、修复ios激励广告穿透参数 186 | 187 | 188 | ## 1.0.3 189 | 190 | * 1、优化api 191 | * 2、升级sdk版本 192 | 193 | 194 | ## 1.0.2 195 | 196 | * 1、优化api 197 | * 2、fix bug 198 | 199 | 200 | ## 1.0.1 201 | 202 | * 1、新增激励广告扩展参数 203 | * 2、fix bug 204 | 205 | ## 1.0.0 206 | 207 | * 1、增加ios端广告 208 | * 2、优化api 209 | 210 | ## 0.0.6 211 | 212 | * 1、优化API 213 | 214 | ## 0.0.5 215 | 216 | * 1、优化API 217 | 218 | ## 0.0.4 219 | 220 | * 1、优化动态信息流/横幅/视频贴片广告加载方式 221 | 222 | ## 0.0.3 223 | 224 | * 1、fix bug 225 | 226 | 227 | ## 0.0.2 228 | 229 | * 1、完善android 激励广告、开屏广告、banner广告、动态信息流/横幅/视频贴片广告 230 | 231 | ## 0.0.1 232 | 233 | * Describe initial release. -------------------------------------------------------------------------------- /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 'com.gstory.flutter_tencentad' 2 | version '1.0-SNAPSHOT' 3 | 4 | buildscript { 5 | ext.kotlin_version = '1.6.10' 6 | repositories { 7 | google() 8 | jcenter() 9 | } 10 | 11 | dependencies { 12 | classpath 'com.android.tools.build:gradle:7.1.2' 13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 14 | } 15 | } 16 | 17 | rootProject.allprojects { 18 | repositories { 19 | google() 20 | jcenter() 21 | flatDir { 22 | dirs project(':flutter_tencentad').file('libs') 23 | } 24 | } 25 | } 26 | 27 | apply plugin: 'com.android.library' 28 | apply plugin: 'kotlin-android' 29 | 30 | android { 31 | namespace = "com.gstory.flutter_tencentad" 32 | compileSdkVersion 31 33 | 34 | compileOptions { 35 | sourceCompatibility JavaVersion.VERSION_1_8 36 | targetCompatibility JavaVersion.VERSION_1_8 37 | } 38 | 39 | kotlinOptions { 40 | jvmTarget = '1.8' 41 | } 42 | 43 | sourceSets { 44 | main.java.srcDirs += 'src/main/kotlin' 45 | } 46 | defaultConfig { 47 | minSdkVersion 16 48 | } 49 | lintOptions { 50 | disable 'InvalidPackage' 51 | } 52 | } 53 | 54 | repositories { 55 | flatDir { 56 | dirs 'libs' 57 | } 58 | } 59 | 60 | dependencies { 61 | api fileTree(dir: 'libs', include: ['*.jar']) 62 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 63 | implementation 'com.qq.e.union:union:4.640.1510' 64 | // implementation(name: 'GDTSDK.unionNormal.4.611.1481', ext: 'aar') 65 | // implementation 'com.qq.e.union:tools:+' 66 | } 67 | -------------------------------------------------------------------------------- /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-5.6.2-all.zip 6 | -------------------------------------------------------------------------------- /android/proguard-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gstory0404/flutter_tencentad/c440bd67180ffec13a3a822ae8c18ee436f3a2d4/android/proguard-rules.pro -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'flutter_tencentad' 2 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 11 | 14 | 15 | 16 | 21 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /android/src/main/kotlin/com/gstory/flutter_tencentad/DownloadApkConfirmDialog.java: -------------------------------------------------------------------------------- 1 | package com.gstory.flutter_tencentad; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.content.res.Configuration; 7 | import android.text.TextUtils; 8 | import android.util.Log; 9 | import android.view.Gravity; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.view.Window; 13 | import android.view.WindowManager; 14 | import android.webkit.WebResourceError; 15 | import android.webkit.WebResourceRequest; 16 | import android.webkit.WebView; 17 | import android.webkit.WebViewClient; 18 | import android.widget.Button; 19 | import android.widget.FrameLayout; 20 | import android.widget.ImageView; 21 | import android.widget.ProgressBar; 22 | 23 | import com.qq.e.comm.compliance.DownloadConfirmCallBack; 24 | 25 | 26 | public class DownloadApkConfirmDialog extends Dialog implements View.OnClickListener { 27 | private static final String TAG = "ConfirmDialogWebView"; 28 | private Context context; 29 | private int orientation; 30 | private DownloadConfirmCallBack callBack; 31 | private WebView webView; 32 | private ImageView close; 33 | private Button confirm; 34 | 35 | private ViewGroup contentHolder; 36 | private ProgressBar loadingBar; 37 | private Button reloadButton; 38 | 39 | private String url; 40 | private boolean urlLoadError = false; 41 | 42 | private static final String RELOAD_TEXT = "重新加载"; 43 | private static final String LOAD_ERROR_TEXT = "抱歉,应用信息获取失败"; 44 | 45 | public DownloadApkConfirmDialog(Context context, String infoUrl, 46 | DownloadConfirmCallBack callBack) { 47 | super(context, R.style.DownloadConfirmDialogFullScreen);//需要全屏显示,同时显示非窗口蒙版 48 | this.context = context; 49 | this.callBack = callBack; 50 | this.url = infoUrl; 51 | orientation = context.getResources().getConfiguration().orientation; 52 | requestWindowFeature(Window.FEATURE_NO_TITLE); 53 | setCanceledOnTouchOutside(true); 54 | initView(); 55 | } 56 | 57 | private void initView() { 58 | setContentView(R.layout.download_confirm_dialog); 59 | View root = findViewById(R.id.download_confirm_root); 60 | if (orientation == Configuration.ORIENTATION_PORTRAIT) { 61 | root.setBackgroundResource(R.drawable.download_confirm_background_portrait); 62 | } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) { 63 | root.setBackgroundResource(R.drawable.download_confirm_background_landscape); 64 | } 65 | close = findViewById(R.id.download_confirm_close); 66 | close.setOnClickListener(this); 67 | reloadButton = findViewById(R.id.download_confirm_reload_button); 68 | reloadButton.setOnClickListener(this); 69 | confirm = findViewById(R.id.download_confirm_confirm); 70 | confirm.setOnClickListener(this); 71 | loadingBar = findViewById(R.id.download_confirm_progress_bar); 72 | contentHolder = findViewById(R.id.download_confirm_content); 73 | createTextView(); 74 | } 75 | 76 | private void createTextView(){ 77 | FrameLayout layout = findViewById(R.id.download_confirm_holder); 78 | webView = new WebView(context); 79 | webView.getSettings().setJavaScriptEnabled(true); 80 | webView.setWebViewClient(new Client()); 81 | layout.addView(webView); 82 | } 83 | @Override 84 | public void show() { 85 | super.show(); 86 | try { 87 | loadUrl(url); 88 | } catch (Exception e) { 89 | Log.e(DownloadApkConfirmDialog.TAG, "load error url:" + url, e); 90 | } 91 | } 92 | 93 | 94 | private void loadUrl(String url) { 95 | if (TextUtils.isEmpty(url)) { 96 | loadingBar.setVisibility(View.GONE); 97 | contentHolder.setVisibility(View.GONE); 98 | reloadButton.setVisibility(View.VISIBLE); 99 | reloadButton.setText(LOAD_ERROR_TEXT); 100 | reloadButton.setEnabled(false); 101 | return; 102 | } 103 | urlLoadError = false; 104 | Log.d(TAG, "download confirm load url:" + url); 105 | webView.loadUrl(url); 106 | } 107 | 108 | public void setInstallTip() { 109 | confirm.setText("立即安装"); 110 | } 111 | 112 | @Override 113 | protected void onStart() { 114 | int height = (int) UIUtils.INSTANCE.getScreenHeight(context); 115 | int width =(int) UIUtils.INSTANCE.getScreenWidth(context); 116 | Window window = getWindow(); 117 | window.getDecorView().setPadding(0, 0, 0, 0); 118 | WindowManager.LayoutParams layoutParams = window.getAttributes(); 119 | if (orientation == Configuration.ORIENTATION_PORTRAIT) { 120 | layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; 121 | layoutParams.height = (int) (height * 0.6); 122 | layoutParams.gravity = Gravity.BOTTOM; 123 | layoutParams.windowAnimations = R.style.DownloadConfirmDialogAnimationUp; 124 | } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) { 125 | layoutParams.width = (int) (width * 0.5); 126 | layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT; 127 | layoutParams.gravity = Gravity.RIGHT; 128 | layoutParams.windowAnimations = R.style.DownloadConfirmDialogAnimationRight; 129 | } 130 | //弹窗外区域蒙版50%透明度 131 | layoutParams.dimAmount = 0.5f; 132 | 133 | //resume后动画会重复,在显示出来后重置无动画 134 | window.setAttributes(layoutParams); 135 | setOnShowListener(new OnShowListener() { 136 | @Override 137 | public void onShow(DialogInterface dialog) { 138 | try { 139 | Window window = getWindow(); 140 | window.setWindowAnimations(0); 141 | } catch (Throwable t) { 142 | } 143 | } 144 | }); 145 | } 146 | 147 | @Override 148 | public void onClick(View v) { 149 | if (v == close) { 150 | if (callBack != null) { 151 | callBack.onCancel(); 152 | } 153 | dismiss(); 154 | } else if (v == confirm) { 155 | if (callBack != null) { 156 | callBack.onConfirm(); 157 | } 158 | dismiss(); 159 | } else if (v == reloadButton) { 160 | loadUrl(url); 161 | } 162 | 163 | } 164 | 165 | @Override 166 | public void cancel() { 167 | super.cancel(); 168 | if (callBack != null) { 169 | callBack.onCancel(); 170 | } 171 | } 172 | 173 | class Client extends WebViewClient { 174 | @Override 175 | public void onPageFinished(WebView view, String url) { 176 | super.onPageFinished(view, url); 177 | if (!urlLoadError) { 178 | loadingBar.setVisibility(View.GONE); 179 | reloadButton.setVisibility(View.GONE); 180 | contentHolder.setVisibility(View.VISIBLE); 181 | } 182 | } 183 | 184 | @Override 185 | public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { 186 | super.onReceivedError(view, request, error); 187 | Log.d(TAG, "doConfirmWithInfo onReceivedError:" + error + " " + request); 188 | urlLoadError = true; 189 | loadingBar.setVisibility(View.GONE); 190 | contentHolder.setVisibility(View.GONE); 191 | reloadButton.setVisibility(View.VISIBLE); 192 | reloadButton.setText(RELOAD_TEXT); 193 | reloadButton.setEnabled(true); 194 | } 195 | } 196 | 197 | 198 | } 199 | -------------------------------------------------------------------------------- /android/src/main/kotlin/com/gstory/flutter_tencentad/FlutterTencentAdConfig.kt: -------------------------------------------------------------------------------- 1 | package com.gstory.flutter_tencentad 2 | 3 | /** 4 | * @Description: 描述 5 | * @Author: gstory 6 | * @CreateDate: 2021/8/7 17:49 7 | **/ 8 | class FlutterTencentAdConfig { 9 | 10 | companion object { 11 | //event事件 12 | const val adevent = "com.gstory.flutter_tencentad/adevent" 13 | //BannerAdView 14 | const val bannerAdView = "com.gstory.flutter_tencentad/BannerAdView" 15 | //SplashAdView 16 | const val splashAdView = "com.gstory.flutter_tencentad/SplashAdView" 17 | //NativeExpressADView 18 | const val nativeAdView = "com.gstory.flutter_tencentad/NativeExpressAdView" 19 | } 20 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/com/gstory/flutter_tencentad/FlutterTencentAdEventPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.gstory.flutter_unionad 2 | 3 | import android.content.Context 4 | import com.gstory.flutter_tencentad.FlutterTencentAdConfig 5 | import io.flutter.embedding.engine.plugins.FlutterPlugin 6 | import io.flutter.plugin.common.EventChannel 7 | 8 | /** 9 | * @Description: 10 | * @Author: gstory0404@gmail 11 | * @CreateDate: 2020/8/19 18:52 12 | */ 13 | class FlutterTencentAdEventPlugin : FlutterPlugin, EventChannel.StreamHandler { 14 | 15 | companion object { 16 | private var eventChannel: EventChannel? = null 17 | 18 | private var eventSink: EventChannel.EventSink? = null 19 | 20 | private var context: Context? = null 21 | 22 | fun sendContent(content: MutableMap) { 23 | eventSink?.success(content); 24 | } 25 | } 26 | 27 | override fun onListen(arguments: Any?, events: EventChannel.EventSink?) { 28 | eventSink = events 29 | } 30 | 31 | override fun onCancel(arguments: Any?) { 32 | eventSink = null 33 | } 34 | 35 | override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) { 36 | eventChannel = EventChannel(binding.binaryMessenger, FlutterTencentAdConfig.adevent) 37 | eventChannel!!.setStreamHandler(this) 38 | context = binding.applicationContext 39 | } 40 | 41 | override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { 42 | eventChannel = null 43 | eventChannel!!.setStreamHandler(null) 44 | } 45 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/com/gstory/flutter_tencentad/FlutterTencentAdViewPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.gstory.flutter_tencentad 2 | 3 | import android.app.Activity 4 | import com.gstory.flutter_tencentad.bannerad.BannerAdViewFactory 5 | import com.gstory.flutter_tencentad.expressad.NativeExpressAdViewFactory 6 | import com.gstory.flutter_tencentad.splashad.SplashAdViewFactory 7 | import io.flutter.embedding.engine.plugins.FlutterPlugin 8 | 9 | /** 10 | * @Description: 11 | * @Author: gstory0404@gmail 12 | * @CreateDate: 2021/8/7 11:38 13 | */ 14 | 15 | object FlutterTencentAdViewPlugin { 16 | fun registerWith(binding: FlutterPlugin.FlutterPluginBinding, activity: Activity) { 17 | //注册banner广告 18 | binding.platformViewRegistry.registerViewFactory(FlutterTencentAdConfig.bannerAdView, BannerAdViewFactory(binding.binaryMessenger, activity)) 19 | //注册splash广告 20 | binding.platformViewRegistry.registerViewFactory(FlutterTencentAdConfig.splashAdView, SplashAdViewFactory(binding.binaryMessenger,activity)) 21 | //注册Express广告 22 | binding.platformViewRegistry.registerViewFactory(FlutterTencentAdConfig.nativeAdView, NativeExpressAdViewFactory(binding.binaryMessenger,activity)) 23 | } 24 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/com/gstory/flutter_tencentad/FlutterTencentadPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.gstory.flutter_tencentad 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.content.Intent 6 | import androidx.annotation.NonNull 7 | import com.gstory.flutter_tencentad.interstitialad.InterstitialAd 8 | import com.gstory.flutter_tencentad.rewardvideoad.RewardVideoAd 9 | import com.gstory.flutter_unionad.FlutterTencentAdEventPlugin 10 | import com.qq.e.comm.DownloadService 11 | import com.qq.e.comm.managers.GDTAdSdk 12 | import com.qq.e.comm.managers.setting.GlobalSetting 13 | import com.qq.e.comm.managers.status.SDKStatus 14 | //import com.qq.e.union.tools.ToolsActivity 15 | import io.flutter.embedding.engine.plugins.FlutterPlugin 16 | import io.flutter.embedding.engine.plugins.activity.ActivityAware 17 | import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding 18 | import io.flutter.plugin.common.MethodCall 19 | import io.flutter.plugin.common.MethodChannel 20 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler 21 | import io.flutter.plugin.common.MethodChannel.Result 22 | 23 | 24 | /** FlutterTencentadPlugin */ 25 | class FlutterTencentadPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { 26 | 27 | private lateinit var channel: MethodChannel 28 | private var applicationContext: Context? = null 29 | private var mActivity: Activity? = null 30 | private var mFlutterPluginBinding: FlutterPlugin.FlutterPluginBinding? = null 31 | 32 | override fun onAttachedToActivity(binding: ActivityPluginBinding) { 33 | mActivity = binding.activity 34 | // Log.e("FlutterUnionadPlugin->","onAttachedToActivity") 35 | FlutterTencentAdViewPlugin.registerWith(mFlutterPluginBinding!!, mActivity!!) 36 | } 37 | 38 | override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { 39 | mActivity = binding.activity 40 | // Log.e("FlutterUnionadPlugin->","onReattachedToActivityForConfigChanges") 41 | } 42 | 43 | override fun onDetachedFromActivityForConfigChanges() { 44 | mActivity = null 45 | // Log.e("FlutterUnionadPlugin->","onDetachedFromActivityForConfigChanges") 46 | } 47 | 48 | override fun onDetachedFromActivity() { 49 | mActivity = null 50 | // Log.e("FlutterUnionadPlugin->","onDetachedFromActivity") 51 | } 52 | 53 | override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { 54 | channel = MethodChannel(flutterPluginBinding.binaryMessenger, "flutter_tencentad") 55 | channel.setMethodCallHandler(this) 56 | applicationContext = flutterPluginBinding.applicationContext 57 | mFlutterPluginBinding = flutterPluginBinding 58 | FlutterTencentAdEventPlugin().onAttachedToEngine(flutterPluginBinding) 59 | } 60 | 61 | override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { 62 | //注册初始化 63 | if (call.method == "register") { 64 | var arguments = call.arguments as Map 65 | val appId = arguments["androidId"] as String 66 | val debug = arguments["debug"] as Boolean 67 | val channelId = arguments["channelId"] as Int 68 | val personalized = arguments["personalized"] as Int 69 | //隐私管理 70 | val androidPrivacy = arguments["androidPrivacy"] as Map? 71 | val convOptimizelnfo = arguments["convOptimizelnfo"] as Map? 72 | 73 | val enableCollectAppInstallStatus = arguments["enableCollectAppInstallStatus"] as Boolean? 74 | 75 | //日志 76 | LogUtil.setAppName("flutter_tencentad") 77 | LogUtil.setShow(debug!!) 78 | //是否开启个性化 79 | GlobalSetting.setPersonalizedState(personalized!!) 80 | //设置渠道id 81 | GlobalSetting.setChannel(channelId!!) 82 | GlobalSetting.setAgreeReadPrivacyInfo(androidPrivacy); 83 | 84 | // 安卓隐私合规,设置是否收集应用安装状态 85 | // https://e.qq.com/dev/help_detail.html?cid=3607&pid=10118 86 | if(enableCollectAppInstallStatus != null){ 87 | // 建议在初始化 SDK 前进行此设置 88 | GlobalSetting.setEnableCollectAppInstallStatus(enableCollectAppInstallStatus); 89 | } 90 | //关闭应用安装监听状态 91 | GlobalSetting.setConvOptimizeInfo(convOptimizelnfo) 92 | 93 | GDTAdSdk.initWithoutStart(applicationContext, appId) 94 | GDTAdSdk.start(object : GDTAdSdk.OnStartListener { 95 | override fun onStartSuccess() { 96 | result.success(true) 97 | } 98 | 99 | override fun onStartFailed(p0: Exception?) { 100 | result.success(false) 101 | } 102 | 103 | }) 104 | //获取sdk版本 105 | } else if (call.method == "getSDKVersion") { 106 | result.success(SDKStatus.getIntegrationSDKVersion()) 107 | //预加载激励广告 108 | } else if (call.method == "loadRewardVideoAd") { 109 | RewardVideoAd.init(applicationContext!!, call.arguments as Map<*, *>) 110 | result.success(true) 111 | //展示激励广告 112 | } else if (call.method == "showRewardVideoAd") { 113 | RewardVideoAd.showAd(call.arguments as Map<*, *>) 114 | result.success(true) 115 | //预加载插屏广告 116 | } else if (call.method == "loadInterstitialAD") { 117 | InterstitialAd.init(mActivity!!, call.arguments as Map<*, *>) 118 | result.success(true) 119 | //展示插屏广告 120 | } else if (call.method == "showInterstitialAD") { 121 | InterstitialAd.showAd(call.arguments as Map<*, *>) 122 | result.success(true) 123 | //进入下载列表 124 | } else if (call.method == "enterAPPDownloadListPage") { 125 | DownloadService.enterAPPDownloadListPage(mActivity) 126 | result.success(true) 127 | //广告助手 128 | } else if (call.method == "enterADTools") { 129 | // mActivity?.startActivity(Intent(applicationContext, ToolsActivity::class.java)) 130 | result.success(true) 131 | } else { 132 | result.notImplemented() 133 | } 134 | } 135 | 136 | override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { 137 | channel.setMethodCallHandler(null) 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /android/src/main/kotlin/com/gstory/flutter_tencentad/LogUtil.kt: -------------------------------------------------------------------------------- 1 | package com.gstory.flutter_tencentad 2 | 3 | import android.text.TextUtils 4 | import android.util.Log 5 | 6 | 7 | /** 8 | * @Description: 打印工具类 9 | * @Author: gstory 10 | * @CreateDate: 2021/8/6 17:51 11 | **/ 12 | 13 | /** 14 | * 15 | * 可自动把调用位置所在的类名和方法名作为tag,并可设置打印级别 16 | * dway 17 | */ 18 | object LogUtil { 19 | //以下为打印级别,级别从低到高 20 | const val LOG_LEVEL_VERBOSE = 1 21 | const val LOG_LEVEL_DEBUG = 2 22 | const val LOG_LEVEL_INFO = 3 23 | const val LOG_LEVEL_WARN = 4 24 | const val LOG_LEVEL_ERROR = 5 25 | const val LOG_LEVEL_NOLOG = 6 26 | private var AppName = "" 27 | private var PrintLine = false 28 | private var LogLevel = LOG_LEVEL_VERBOSE 29 | private var isShow = false 30 | 31 | /** 32 | * 可在打印的TAG前添加应用名标识,不设置则不输出 33 | */ 34 | fun setAppName(appName: String) { 35 | AppName = appName 36 | } 37 | 38 | /** 39 | * 是否输出打印所在的行数,默认不输出 40 | */ 41 | fun setPrintLine(enable: Boolean) { 42 | PrintLine = enable 43 | } 44 | 45 | /** 46 | * 可在打印的TAG前添加应用名标识,不设置则不输出 47 | */ 48 | fun setShow(show: Boolean) { 49 | isShow = show 50 | } 51 | 52 | 53 | /** 54 | * 设置打印级别,且只有等于或高于该级别的打印才会输出 55 | */ 56 | fun setLogLevel(logLevel: Int) { 57 | LogLevel = logLevel 58 | } 59 | 60 | fun v() { 61 | log(LOG_LEVEL_VERBOSE, "") 62 | } 63 | 64 | fun d() { 65 | log(LOG_LEVEL_DEBUG, "") 66 | } 67 | 68 | fun i() { 69 | log(LOG_LEVEL_INFO, "") 70 | } 71 | 72 | fun w() { 73 | log(LOG_LEVEL_WARN, "") 74 | } 75 | 76 | fun e() { 77 | log(LOG_LEVEL_ERROR, "") 78 | } 79 | 80 | fun v(msg: String) { 81 | if (LogLevel <= LOG_LEVEL_VERBOSE) { 82 | log(LOG_LEVEL_VERBOSE, msg) 83 | } 84 | } 85 | 86 | fun d(msg: String) { 87 | if (LogLevel <= LOG_LEVEL_DEBUG) { 88 | log(LOG_LEVEL_DEBUG, msg) 89 | } 90 | } 91 | 92 | fun i(msg: String) { 93 | if (LogLevel <= LOG_LEVEL_INFO) { 94 | log(LOG_LEVEL_INFO, msg) 95 | } 96 | } 97 | 98 | fun w(msg: String) { 99 | if (LogLevel <= LOG_LEVEL_WARN) { 100 | log(LOG_LEVEL_WARN, msg) 101 | } 102 | } 103 | 104 | fun e(msg: String) { 105 | if (LogLevel <= LOG_LEVEL_ERROR) { 106 | log(LOG_LEVEL_ERROR, msg) 107 | } 108 | } 109 | 110 | private fun log(logLevel: Int, msg: String) { 111 | if(!isShow){ 112 | return 113 | } 114 | val caller = Thread.currentThread().stackTrace[4] 115 | var callerClazzName = caller.className 116 | if (callerClazzName.contains(".")) { 117 | callerClazzName = callerClazzName.substring(callerClazzName.lastIndexOf(".") + 1) 118 | } 119 | if (callerClazzName.contains("$")) { 120 | callerClazzName = callerClazzName.substring(0, callerClazzName.indexOf("$")) 121 | } 122 | var tag = callerClazzName 123 | if (!TextUtils.isEmpty(AppName)) { 124 | tag = AppName + "_" + tag 125 | } 126 | if (PrintLine) { 127 | tag += "(Line:%d)" 128 | tag = String.format(tag, caller.lineNumber) 129 | } 130 | tag = String.format(tag, callerClazzName) 131 | val message = "---" + caller.methodName + "---" + msg 132 | when (logLevel) { 133 | LOG_LEVEL_VERBOSE -> Log.v(tag, message) 134 | LOG_LEVEL_DEBUG -> Log.d(tag, message) 135 | LOG_LEVEL_INFO -> Log.i(tag, message) 136 | LOG_LEVEL_WARN -> Log.w(tag, message) 137 | LOG_LEVEL_ERROR -> Log.e(tag, message) 138 | LOG_LEVEL_NOLOG -> { 139 | } 140 | } 141 | } 142 | } 143 | 144 | -------------------------------------------------------------------------------- /android/src/main/kotlin/com/gstory/flutter_tencentad/bannerad/BannerAdView.kt: -------------------------------------------------------------------------------- 1 | package com.gstory.flutter_tencentad.bannerad 2 | 3 | import android.app.Activity 4 | import android.util.Log 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import android.widget.FrameLayout 8 | import com.gstory.flutter_tencentad.* 9 | import com.qq.e.ads.banner2.UnifiedBannerADListener 10 | import com.qq.e.ads.banner2.UnifiedBannerView 11 | import com.qq.e.comm.pi.IBidding 12 | import com.qq.e.comm.util.AdError 13 | import io.flutter.plugin.common.BinaryMessenger 14 | import io.flutter.plugin.common.MethodCall 15 | import io.flutter.plugin.common.MethodChannel 16 | import io.flutter.plugin.platform.PlatformView 17 | 18 | /** 19 | * @Description: 平台模板Banner广告 20 | * @Author: gstory 21 | * @CreateDate: 2021/8/7 17:43 22 | **/ 23 | 24 | internal class BannerAdView( 25 | var activity: Activity, messenger: BinaryMessenger, id: Int, params: Map 26 | ) : PlatformView, UnifiedBannerADListener, MethodChannel.MethodCallHandler { 27 | 28 | private val TAG = "BannerAdView" 29 | 30 | private var mContainer: FrameLayout? = null 31 | 32 | //广告所需参数 33 | private var codeId: String 34 | private var viewWidth: Float 35 | private var viewHeight: Float 36 | 37 | private var unifiedBannerView: UnifiedBannerView? = null 38 | 39 | private var channel: MethodChannel? 40 | 41 | private var downloadConfirm: Boolean 42 | 43 | //是否开启竞价 44 | private var isBidding: Boolean = params["isBidding"] as Boolean 45 | 46 | 47 | init { 48 | codeId = params["androidId"] as String 49 | var width = params["viewWidth"] as Double 50 | var height = params["viewHeight"] as Double 51 | downloadConfirm = params["downloadConfirm"] as Boolean 52 | viewWidth = width.toFloat() 53 | viewHeight = height.toFloat() 54 | mContainer = FrameLayout(activity) 55 | mContainer?.layoutParams?.width = ViewGroup.LayoutParams.WRAP_CONTENT 56 | mContainer?.layoutParams?.height = ViewGroup.LayoutParams.WRAP_CONTENT 57 | channel = MethodChannel(messenger, FlutterTencentAdConfig.bannerAdView + "_" + id) 58 | channel?.setMethodCallHandler(this) 59 | loadBannerAd() 60 | } 61 | 62 | private fun loadBannerAd() { 63 | unifiedBannerView = UnifiedBannerView(activity, codeId, this) 64 | unifiedBannerView?.loadAD() 65 | } 66 | 67 | override fun getView(): View { 68 | return mContainer!! 69 | } 70 | 71 | 72 | //广告加载失败,error 对象包含了错误码和错误信息 73 | override fun onNoAD(p0: AdError?) { 74 | LogUtil.e("$TAG Banner广告加载失败 ${p0?.errorCode} ${p0?.errorMsg}") 75 | var map: MutableMap = 76 | mutableMapOf("code" to p0?.errorCode, "message" to p0?.errorMsg) 77 | channel?.invokeMethod("onFail", map) 78 | } 79 | 80 | //广告加载成功回调,表示广告相关的资源已经加载完毕,Ready To Show 81 | override fun onADReceive() { 82 | mContainer?.removeAllViews() 83 | if (unifiedBannerView == null) { 84 | LogUtil.e("$TAG Banner广告加载失败 unifiedBannerView不存在或已销毁") 85 | var map: MutableMap = 86 | mutableMapOf("code" to 0, "message" to "BannerView不存在或已销毁") 87 | channel?.invokeMethod("onFail", map) 88 | return 89 | } 90 | if (downloadConfirm) { 91 | unifiedBannerView?.setDownloadConfirmListener(DownloadConfirmHelper.DOWNLOAD_CONFIRM_LISTENER) 92 | } 93 | //竞价 则返回价格 不直接加载 94 | if (isBidding) { 95 | channel?.invokeMethod( 96 | "onECPM", mutableMapOf( 97 | "ecpmLevel" to unifiedBannerView?.ecpmLevel, "ecpm" to unifiedBannerView?.ecpm 98 | ) 99 | ) 100 | } else { 101 | LogUtil.e("$TAG Banner广告加载成功回调") 102 | mContainer?.addView( 103 | unifiedBannerView, FrameLayout.LayoutParams(viewWidth.toInt(), viewHeight.toInt()) 104 | ) 105 | val map: MutableMap = mutableMapOf( 106 | // "width" to UIUtils.px2dip(activity, unifiedBannerView?.width!!.toFloat()), 107 | // "height" to UIUtils.px2dip(activity, unifiedBannerView?.height!!.toFloat()) 108 | "width" to viewWidth.toInt(), 109 | "height" to viewHeight.toInt() 110 | ) 111 | channel?.invokeMethod("onShow", map) 112 | } 113 | } 114 | 115 | //当广告曝光时发起的回调 116 | override fun onADExposure() { 117 | LogUtil.e("$TAG Banner广告曝光") 118 | channel?.invokeMethod("onExpose", "") 119 | } 120 | 121 | //当广告关闭时调用 122 | override fun onADClosed() { 123 | LogUtil.e("$TAG Banner广告关闭") 124 | channel?.invokeMethod("onClose", "") 125 | } 126 | 127 | //当广告点击时发起的回调,由于点击去重等原因可能和平台最终的统计数据有差异 128 | override fun onADClicked() { 129 | LogUtil.e("$TAG Banner广告点击") 130 | channel?.invokeMethod("onClick", "") 131 | } 132 | 133 | //由于广告点击离开 APP 时调用 134 | override fun onADLeftApplication() { 135 | LogUtil.e("$TAG Banner广告点击离开 APP") 136 | } 137 | 138 | override fun dispose() { 139 | unifiedBannerView?.destroy() 140 | unifiedBannerView = null 141 | } 142 | 143 | override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { 144 | when (call.method) { 145 | //竞价成功 146 | "biddingSucceeded" -> { 147 | var arguments = call.arguments as Map<*, *> 148 | val map: MutableMap = mutableMapOf( 149 | //对应值为竞胜出价,类型为Integer 150 | IBidding.EXPECT_COST_PRICE to arguments["expectCostPrice"], 151 | //对应值为最大竞败方出价,类型为Integer 152 | IBidding.HIGHEST_LOSS_PRICE to arguments["highestLossPrice"], 153 | ) 154 | unifiedBannerView?.sendWinNotification(map) 155 | //展示banner 156 | mContainer?.addView(unifiedBannerView) 157 | val map2: MutableMap = mutableMapOf( 158 | "width" to UIUtils.px2dip(activity, unifiedBannerView?.width!!.toFloat()), 159 | "height" to UIUtils.px2dip(activity, unifiedBannerView?.height!!.toFloat()) 160 | ) 161 | channel?.invokeMethod("onShow", map2) 162 | } 163 | //竞价失败 164 | "biddingFail" -> { 165 | var arguments = call.arguments as Map<*, *> 166 | val map: MutableMap = mutableMapOf( 167 | //值为本次竞胜方出价(单位:分),类型为Integer。选填 168 | IBidding.WIN_PRICE to arguments["winPrice"], 169 | //值为优量汇广告竞败原因,类型为Integer。必填 170 | IBidding.LOSS_REASON to arguments["lossReason"], 171 | //值为本次竞胜方渠道ID,类型为Integer。必填。 172 | IBidding.ADN_ID to arguments["adnId"], 173 | ) 174 | unifiedBannerView?.sendLossNotification(map) 175 | } 176 | 177 | } 178 | } 179 | 180 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/com/gstory/flutter_tencentad/bannerad/BannerAdViewFactory.kt: -------------------------------------------------------------------------------- 1 | package com.gstory.flutter_tencentad.bannerad 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 | 10 | /** 11 | * @Description: 描述 12 | * @Author: gstory 13 | * @CreateDate: 2021/8/7 17:42 14 | **/ 15 | 16 | internal class BannerAdViewFactory(private val messenger: BinaryMessenger, private val activity: Activity) : PlatformViewFactory( 17 | StandardMessageCodec.INSTANCE) { 18 | 19 | override fun create(context: Context?, viewId: Int, args: Any?): PlatformView { 20 | val params = args as Map 21 | return BannerAdView(activity,messenger, viewId, params) 22 | } 23 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/com/gstory/flutter_tencentad/expressad/NativeExpressAdViewFactory.kt: -------------------------------------------------------------------------------- 1 | package com.gstory.flutter_tencentad.expressad 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 | 10 | /** 11 | * @Description: 描述 12 | * @Author: gstory 13 | * @CreateDate: 2021/8/7 17:42 14 | **/ 15 | 16 | internal class NativeExpressAdViewFactory(private val messenger: BinaryMessenger, private val activity: Activity) : PlatformViewFactory( 17 | StandardMessageCodec.INSTANCE) { 18 | 19 | override fun create(context: Context?, viewId: Int, args: Any?): PlatformView { 20 | val params = args as Map 21 | return NativeExpressAdView(activity,messenger, viewId, params) 22 | } 23 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/com/gstory/flutter_tencentad/rewardvideoad/RewardVideoAd.kt: -------------------------------------------------------------------------------- 1 | package com.gstory.flutter_tencentad.rewardvideoad 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import com.gstory.flutter_tencentad.DownloadApkConfirmDialog 6 | import com.gstory.flutter_tencentad.DownloadConfirmHelper 7 | import com.gstory.flutter_tencentad.LogUtil 8 | import com.gstory.flutter_tencentad.interstitialad.InterstitialAd 9 | import com.gstory.flutter_unionad.FlutterTencentAdEventPlugin 10 | import com.qq.e.ads.rewardvideo.RewardVideoAD 11 | import com.qq.e.ads.rewardvideo.RewardVideoADListener 12 | import com.qq.e.ads.rewardvideo.ServerSideVerificationOptions 13 | import com.qq.e.comm.pi.IBidding 14 | import com.qq.e.comm.util.AdError 15 | 16 | 17 | @SuppressLint("StaticFieldLeak") 18 | object RewardVideoAd { 19 | private val TAG = "RewardVideoAd" 20 | 21 | private lateinit var context: Context 22 | private var rewardVideoAD: RewardVideoAD? = null 23 | 24 | private var codeId: String? = null 25 | private var userID: String = "" 26 | private var rewardName: String = "" 27 | private var rewardAmount: Int = 0 28 | private var customData: String = "" 29 | private var downloadConfirm: Boolean = false 30 | private var videoMuted: Boolean = false 31 | 32 | //是否开启竞价 33 | private var isBidding: Boolean = false 34 | 35 | fun init(context: Context, params: Map<*, *>) { 36 | this.context = context 37 | this.codeId = params["androidId"] as String 38 | this.userID = params["userID"] as String 39 | this.rewardName = params["rewardName"] as String 40 | this.rewardAmount = params["rewardAmount"] as Int 41 | this.customData = params["customData"] as String 42 | this.downloadConfirm = params["downloadConfirm"] as Boolean 43 | this.isBidding = params["isBidding"] as Boolean 44 | this.videoMuted = params["videoMuted"] as Boolean 45 | loadRewardVideoAd() 46 | } 47 | 48 | private fun loadRewardVideoAd() { 49 | rewardVideoAD = RewardVideoAD(context, codeId, rewardVideoADListener,videoMuted) 50 | var options = ServerSideVerificationOptions.Builder() 51 | .setUserId(userID) 52 | .setCustomData(customData) 53 | .build() 54 | rewardVideoAD?.setServerSideVerificationOptions(options) 55 | rewardVideoAD?.loadAD() 56 | } 57 | 58 | fun showAd(params: Map<*, *>) { 59 | if (rewardVideoAD == null) { 60 | var map: MutableMap = 61 | mutableMapOf("adType" to "rewardAd", "onAdMethod" to "onUnReady") 62 | FlutterTencentAdEventPlugin.sendContent(map) 63 | return 64 | } 65 | //是否为竞价模式 66 | if (isBidding) { 67 | var isSuccess: Boolean = params["isSuccess"] as Boolean 68 | //是否成功 69 | if (isSuccess) { 70 | rewardVideoAD?.sendWinNotification( 71 | mutableMapOf( 72 | //对应值为竞胜出价,类型为Integer 73 | IBidding.EXPECT_COST_PRICE to params["expectCostPrice"], 74 | //对应值为最大竞败方出价,类型为Integer 75 | IBidding.HIGHEST_LOSS_PRICE to params["highestLossPrice"], 76 | ) 77 | ) 78 | rewardVideoAD?.showAD() 79 | } else { 80 | rewardVideoAD?.sendLossNotification( 81 | mutableMapOf( 82 | //值为本次竞胜方出价(单位:分),类型为Integer。选填 83 | IBidding.WIN_PRICE to params["winPrice"], 84 | //值为优量汇广告竞败原因,类型为Integer。必填 85 | IBidding.LOSS_REASON to params["lossReason"], 86 | //值为本次竞胜方渠道ID,类型为Integer。必填。 87 | IBidding.ADN_ID to params["adnId"], 88 | ) 89 | ) 90 | } 91 | } else { 92 | rewardVideoAD?.showAD() 93 | } 94 | 95 | } 96 | 97 | private var rewardVideoADListener = object : RewardVideoADListener { 98 | override fun onADLoad() { 99 | LogUtil.e("$TAG 激励广告加载成功") 100 | if (downloadConfirm) { 101 | rewardVideoAD?.setDownloadConfirmListener(DownloadConfirmHelper.DOWNLOAD_CONFIRM_LISTENER) 102 | } 103 | } 104 | 105 | override fun onVideoCached() { 106 | LogUtil.e("$TAG 激励广告视频素材缓存成功") 107 | if (isBidding) { 108 | var map: MutableMap = 109 | mutableMapOf( 110 | "adType" to "rewardAd", 111 | "onAdMethod" to "onECPM", 112 | "ecpmLevel" to rewardVideoAD?.ecpmLevel, 113 | "ecpm" to rewardVideoAD?.ecpm 114 | ) 115 | FlutterTencentAdEventPlugin.sendContent(map) 116 | } else { 117 | var map: MutableMap = 118 | mutableMapOf("adType" to "rewardAd", "onAdMethod" to "onReady") 119 | FlutterTencentAdEventPlugin.sendContent(map) 120 | } 121 | } 122 | 123 | override fun onADShow() { 124 | LogUtil.e("$TAG 激励视频广告页面展示") 125 | var map: MutableMap = 126 | mutableMapOf("adType" to "rewardAd", "onAdMethod" to "onShow") 127 | FlutterTencentAdEventPlugin.sendContent(map) 128 | } 129 | 130 | override fun onADExpose() { 131 | LogUtil.e("$TAG 激励视频广告曝光") 132 | var map: MutableMap = 133 | mutableMapOf("adType" to "rewardAd", "onAdMethod" to "onExpose") 134 | FlutterTencentAdEventPlugin.sendContent(map) 135 | } 136 | 137 | override fun onReward(p0: MutableMap?) { 138 | LogUtil.e("$TAG 激励视频广告激励发放 $p0") 139 | 140 | var map: MutableMap = mutableMapOf( 141 | "adType" to "rewardAd", 142 | "onAdMethod" to "onVerify", 143 | "transId" to p0!!["transId"], 144 | "rewardName" to rewardName, 145 | "rewardAmount" to rewardAmount 146 | ) 147 | FlutterTencentAdEventPlugin.sendContent(map) 148 | } 149 | 150 | override fun onADClick() { 151 | LogUtil.e("$TAG 激励视频广告被点击") 152 | var map: MutableMap = 153 | mutableMapOf("adType" to "rewardAd", "onAdMethod" to "onClick") 154 | FlutterTencentAdEventPlugin.sendContent(map) 155 | } 156 | 157 | override fun onVideoComplete() { 158 | LogUtil.e("$TAG 激励视频广告视频素材播放完毕") 159 | var map: MutableMap = 160 | mutableMapOf("adType" to "rewardAd", "onAdMethod" to "onFinish") 161 | FlutterTencentAdEventPlugin.sendContent(map) 162 | } 163 | 164 | override fun onADClose() { 165 | LogUtil.e("$TAG 激励视频广告被关闭") 166 | var map: MutableMap = 167 | mutableMapOf("adType" to "rewardAd", "onAdMethod" to "onClose") 168 | FlutterTencentAdEventPlugin.sendContent(map) 169 | rewardVideoAD = null 170 | } 171 | 172 | override fun onError(p0: AdError?) { 173 | LogUtil.e("$TAG 广告流程出错 ${p0?.errorCode} ${p0?.errorMsg}") 174 | var map: MutableMap = mutableMapOf( 175 | "adType" to "rewardAd", 176 | "onAdMethod" to "onFail", 177 | "code" to p0?.errorCode, 178 | "message" to p0?.errorMsg 179 | ) 180 | FlutterTencentAdEventPlugin.sendContent(map) 181 | } 182 | 183 | } 184 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/com/gstory/flutter_tencentad/splashad/SplashAdView.kt: -------------------------------------------------------------------------------- 1 | package com.gstory.flutter_tencentad.splashad 2 | 3 | import android.app.Activity 4 | import android.util.Log 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import android.widget.FrameLayout 8 | import com.gstory.flutter_tencentad.DownloadApkConfirmDialog 9 | import com.gstory.flutter_tencentad.DownloadConfirmHelper 10 | import com.gstory.flutter_tencentad.FlutterTencentAdConfig 11 | import com.gstory.flutter_tencentad.LogUtil 12 | import com.qq.e.ads.splash.SplashAD 13 | import com.qq.e.ads.splash.SplashADListener 14 | import com.qq.e.comm.pi.IBidding 15 | import com.qq.e.comm.util.AdError 16 | import io.flutter.plugin.common.BinaryMessenger 17 | import io.flutter.plugin.common.MethodCall 18 | import io.flutter.plugin.common.MethodChannel 19 | import io.flutter.plugin.platform.PlatformView 20 | 21 | 22 | internal class SplashAdView( 23 | var activity: Activity, 24 | messenger: BinaryMessenger, 25 | id: Int, 26 | params: Map 27 | ) : 28 | PlatformView, SplashADListener , MethodChannel.MethodCallHandler { 29 | 30 | private var mContainer: FrameLayout? = null 31 | private var channel: MethodChannel? 32 | 33 | private var splashAD: SplashAD? = null 34 | 35 | //广告所需参数 36 | private var codeId: String = params["androidId"] as String 37 | private var fetchDelay: Int = params["fetchDelay"] as Int 38 | private var downloadConfirm: Boolean = params["downloadConfirm"] as Boolean 39 | //是否开启竞价 40 | private var isBidding: Boolean = params["isBidding"] as Boolean 41 | 42 | init { 43 | mContainer = FrameLayout(activity) 44 | mContainer?.layoutParams?.width = ViewGroup.LayoutParams.WRAP_CONTENT 45 | mContainer?.layoutParams?.height = ViewGroup.LayoutParams.WRAP_CONTENT 46 | channel = MethodChannel(messenger, FlutterTencentAdConfig.splashAdView + "_" + id) 47 | channel?.setMethodCallHandler(this) 48 | loadSplashAd() 49 | } 50 | 51 | private fun loadSplashAd() { 52 | splashAD = SplashAD(activity, codeId, this, fetchDelay) 53 | mContainer?.removeAllViews() 54 | splashAD?.fetchAdOnly() 55 | } 56 | 57 | 58 | override fun getView(): View { 59 | return mContainer!! 60 | } 61 | 62 | /*************开屏广告回调******************/ 63 | //广告关闭时调用,可能是用户关闭或者展示时间到。此时一般需要跳过开屏的 Activity,进入应用内容页面 64 | override fun onADDismissed() { 65 | LogUtil.e("开屏广告关闭") 66 | channel?.invokeMethod("onClose", "") 67 | } 68 | 69 | //广告加载失败,error 对象包含了错误码和错误信息,错误码的详细内容可以参考文档第5章 70 | override fun onNoAD(p0: AdError?) { 71 | LogUtil.e("开屏广告加载失败 ${p0?.errorCode} ${p0?.errorMsg}") 72 | var map: MutableMap = mutableMapOf("code" to p0?.errorCode, "message" to p0?.errorMsg) 73 | channel?.invokeMethod("onFail", map) 74 | } 75 | 76 | //广告成功展示时调用,成功展示不等于有效展示(比如广告容器高度不够) 77 | override fun onADPresent() { 78 | LogUtil.e("开屏广告成功展示") 79 | channel?.invokeMethod("onShow", "") 80 | } 81 | 82 | //广告被点击时调用,不代表满足计费条件(如点击时网络异常) 83 | override fun onADClicked() { 84 | LogUtil.e("开屏广告被点击") 85 | channel?.invokeMethod("onClick", "") 86 | } 87 | 88 | //倒计时回调,返回广告还将被展示的剩余时间,单位是 ms 89 | override fun onADTick(p0: Long) { 90 | LogUtil.e("开屏广告倒计时回调 $p0") 91 | channel?.invokeMethod("onADTick", p0) 92 | } 93 | 94 | //广告曝光时调用 95 | override fun onADExposure() { 96 | LogUtil.e("开屏广告曝光") 97 | channel?.invokeMethod("onExpose", "") 98 | } 99 | 100 | //广告加载成功的回调,在fetchAdOnly的情况下, 101 | // 表示广告拉取成功可以显示了。广告需要在SystemClock.elapsedRealtime { 128 | var arguments = call.arguments as Map<*, *> 129 | splashAD?.sendWinNotification(mutableMapOf( 130 | //对应值为竞胜出价,类型为Integer 131 | IBidding.EXPECT_COST_PRICE to arguments["expectCostPrice"], 132 | //对应值为最大竞败方出价,类型为Integer 133 | IBidding.HIGHEST_LOSS_PRICE to arguments["highestLossPrice"], 134 | )) 135 | //展示banner 136 | splashAD?.showAd(mContainer) 137 | } 138 | //竞价失败 139 | "biddingFail" -> { 140 | var arguments = call.arguments as Map<*, *> 141 | splashAD?.sendLossNotification(mutableMapOf( 142 | //值为本次竞胜方出价(单位:分),类型为Integer。选填 143 | IBidding.WIN_PRICE to arguments["winPrice"], 144 | //值为优量汇广告竞败原因,类型为Integer。必填 145 | IBidding.LOSS_REASON to arguments["lossReason"], 146 | //值为本次竞胜方渠道ID,类型为Integer。必填。 147 | IBidding.ADN_ID to arguments["adnId"], 148 | )) 149 | } 150 | 151 | } 152 | } 153 | } -------------------------------------------------------------------------------- /android/src/main/kotlin/com/gstory/flutter_tencentad/splashad/SplashAdViewFactory.kt: -------------------------------------------------------------------------------- 1 | package com.gstory.flutter_tencentad.splashad 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import com.gstory.flutter_tencentad.bannerad.BannerAdView 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 | 11 | class SplashAdViewFactory (private val messenger: BinaryMessenger, private val activity: Activity) : PlatformViewFactory( 12 | StandardMessageCodec.INSTANCE) { 13 | 14 | override fun create(context: Context?, viewId: Int, args: Any?): PlatformView { 15 | val params = args as Map 16 | return SplashAdView(activity,messenger, viewId, params) 17 | } 18 | } -------------------------------------------------------------------------------- /android/src/main/res/anim/download_confirm_dialog_slide_right_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /android/src/main/res/anim/download_confirm_dialog_slide_up.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /android/src/main/res/drawable/download_confirm_background_confirm.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /android/src/main/res/drawable/download_confirm_background_landscape.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /android/src/main/res/drawable/download_confirm_background_portrait.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /android/src/main/res/drawable/ic_download_confirm_close.xml: -------------------------------------------------------------------------------- 1 | 6 | 12 | 13 | -------------------------------------------------------------------------------- /android/src/main/res/layout/download_confirm_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 19 | 20 | 28 | 36 | 37 | 38 | 39 | 43 | 48 | 49 | 54 | 55 |