diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
index 2a5bca8..4af4d13 100644
--- a/android/src/main/AndroidManifest.xml
+++ b/android/src/main/AndroidManifest.xml
@@ -1,18 +1,15 @@
+
-
-
+ android:resource="@xml/gdt_file_path"
+ tools:replace="android:resource"
+ />
+
+
+
-
+
\ No newline at end of file
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/DownloadApkConfirmDialog.java b/android/src/main/kotlin/com/example/union_ad_ssgf/DownloadApkConfirmDialog.java
new file mode 100644
index 0000000..6df5e06
--- /dev/null
+++ b/android/src/main/kotlin/com/example/union_ad_ssgf/DownloadApkConfirmDialog.java
@@ -0,0 +1,198 @@
+package com.example.union_ad_ssgf;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.Configuration;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.webkit.WebResourceError;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+
+import com.qq.e.comm.compliance.DownloadConfirmCallBack;
+
+
+public class DownloadApkConfirmDialog extends Dialog implements View.OnClickListener {
+ private static final String TAG = "ConfirmDialogWebView";
+ private Context context;
+ private int orientation;
+ private DownloadConfirmCallBack callBack;
+ private WebView webView;
+ private ImageView close;
+ private Button confirm;
+
+ private ViewGroup contentHolder;
+ private ProgressBar loadingBar;
+ private Button reloadButton;
+
+ private String url;
+ private boolean urlLoadError = false;
+
+ private static final String RELOAD_TEXT = "重新加载";
+ private static final String LOAD_ERROR_TEXT = "抱歉,应用信息获取失败";
+
+ public DownloadApkConfirmDialog(Context context, String infoUrl,
+ DownloadConfirmCallBack callBack) {
+ super(context, R.style.DownloadConfirmDialogFullScreen);//需要全屏显示,同时显示非窗口蒙版
+ this.context = context;
+ this.callBack = callBack;
+ this.url = infoUrl;
+ orientation = context.getResources().getConfiguration().orientation;
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ setCanceledOnTouchOutside(true);
+ initView();
+ }
+
+ private void initView() {
+ setContentView(R.layout.download_confirm_dialog);
+ View root = findViewById(R.id.download_confirm_root);
+ if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ root.setBackgroundResource(R.drawable.download_confirm_background_portrait);
+ } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ root.setBackgroundResource(R.drawable.download_confirm_background_landscape);
+ }
+ close = findViewById(R.id.download_confirm_close);
+ close.setOnClickListener(this);
+ reloadButton = findViewById(R.id.download_confirm_reload_button);
+ reloadButton.setOnClickListener(this);
+ confirm = findViewById(R.id.download_confirm_confirm);
+ confirm.setOnClickListener(this);
+ loadingBar = findViewById(R.id.download_confirm_progress_bar);
+ contentHolder = findViewById(R.id.download_confirm_content);
+ createTextView();
+ }
+
+ private void createTextView(){
+ FrameLayout layout = findViewById(R.id.download_confirm_holder);
+ webView = new WebView(context);
+ webView.getSettings().setJavaScriptEnabled(true);
+ webView.setWebViewClient(new Client());
+ layout.addView(webView);
+ }
+ @Override
+ public void show() {
+ super.show();
+ try {
+ loadUrl(url);
+ } catch (Exception e) {
+ Log.e(DownloadApkConfirmDialog.TAG, "load error url:" + url, e);
+ }
+ }
+
+
+ private void loadUrl(String url) {
+ if (TextUtils.isEmpty(url)) {
+ loadingBar.setVisibility(View.GONE);
+ contentHolder.setVisibility(View.GONE);
+ reloadButton.setVisibility(View.VISIBLE);
+ reloadButton.setText(LOAD_ERROR_TEXT);
+ reloadButton.setEnabled(false);
+ return;
+ }
+ urlLoadError = false;
+ Log.d(TAG, "download confirm load url:" + url);
+ webView.loadUrl(url);
+ }
+
+ public void setInstallTip() {
+ confirm.setText("立即安装");
+ }
+
+ @Override
+ protected void onStart() {
+ int height = (int) UIUtils.INSTANCE.getScreenHeight(context);
+ int width =(int) UIUtils.INSTANCE.getScreenWidth(context);
+ Window window = getWindow();
+ window.getDecorView().setPadding(0, 0, 0, 0);
+ WindowManager.LayoutParams layoutParams = window.getAttributes();
+ if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
+ layoutParams.height = (int) (height * 0.6);
+ layoutParams.gravity = Gravity.BOTTOM;
+ layoutParams.windowAnimations = R.style.DownloadConfirmDialogAnimationUp;
+ } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ layoutParams.width = (int) (width * 0.5);
+ layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT;
+ layoutParams.gravity = Gravity.RIGHT;
+ layoutParams.windowAnimations = R.style.DownloadConfirmDialogAnimationRight;
+ }
+ //弹窗外区域蒙版50%透明度
+ layoutParams.dimAmount = 0.5f;
+
+ //resume后动画会重复,在显示出来后重置无动画
+ window.setAttributes(layoutParams);
+ setOnShowListener(new OnShowListener() {
+ @Override
+ public void onShow(DialogInterface dialog) {
+ try {
+ Window window = getWindow();
+ window.setWindowAnimations(0);
+ } catch (Throwable t) {
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v == close) {
+ if (callBack != null) {
+ callBack.onCancel();
+ }
+ dismiss();
+ } else if (v == confirm) {
+ if (callBack != null) {
+ callBack.onConfirm();
+ }
+ dismiss();
+ } else if (v == reloadButton) {
+ loadUrl(url);
+ }
+
+ }
+
+ @Override
+ public void cancel() {
+ super.cancel();
+ if (callBack != null) {
+ callBack.onCancel();
+ }
+ }
+
+ class Client extends WebViewClient {
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ super.onPageFinished(view, url);
+ if (!urlLoadError) {
+ loadingBar.setVisibility(View.GONE);
+ reloadButton.setVisibility(View.GONE);
+ contentHolder.setVisibility(View.VISIBLE);
+ }
+ }
+
+ @Override
+ public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
+ super.onReceivedError(view, request, error);
+ Log.d(TAG, "doConfirmWithInfo onReceivedError:" + error + " " + request);
+ urlLoadError = true;
+ loadingBar.setVisibility(View.GONE);
+ contentHolder.setVisibility(View.GONE);
+ reloadButton.setVisibility(View.VISIBLE);
+ reloadButton.setText(RELOAD_TEXT);
+ reloadButton.setEnabled(true);
+ }
+ }
+
+
+}
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/DownloadConfirmHelper.java b/android/src/main/kotlin/com/example/union_ad_ssgf/DownloadConfirmHelper.java
new file mode 100644
index 0000000..d334d19
--- /dev/null
+++ b/android/src/main/kotlin/com/example/union_ad_ssgf/DownloadConfirmHelper.java
@@ -0,0 +1,818 @@
+package com.example.union_ad_ssgf;
+
+import android.app.Activity;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.qq.e.comm.compliance.ApkDownloadComplianceInterface;
+import com.qq.e.comm.compliance.DownloadConfirmCallBack;
+import com.qq.e.comm.compliance.DownloadConfirmListener;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/*
+ * created by timfeng 2021/2/2
+ */
+public class DownloadConfirmHelper {
+ public static final String TAG = "DownloadConfirmHelper";
+ public static boolean USE_CUSTOM_DIALOG = false;
+
+ private static final String JSON_INFO_PARAMETER = "&resType=api";
+
+ private static final String JSON_RESULT_KEY = "ret";
+ private static final String JSON_DATA_KEY = "data";
+
+ private static final String ICON_URL_KEY = "iconUrl";//App Icon
+ private static final String APP_NAME_KEY = "appName";//App 名称
+ private static final String VERSION_NAME_KEY = "versionName";//版本号
+ private static final String AUTHOR_NAME_KEY = "authorName";//开发者
+ private static final String PERMISSIONS_KEY = "permissions";//权限列表(具体权限信息,非URL)
+ private static final String PRIVACY_AGREEMENT_KEY = "privacyAgreement";//隐私政策(URL)这个url需要使用外部浏览器或者webview展示
+ private static final String UPDATE_TIME_KEY = "apkPublishTime";//版本更新时间
+ private static final String APK_FILE_SIZE_KEY = "fileSize";//apk文件大小,bytes
+
+ private static boolean USE_RAW_PERMISSIONS = false;
+ private static JSONObject PERMISSIONS_MAP_JSON;
+
+ public static class ApkInfo {
+ public String iconUrl;
+ public String appName;
+ public String versionName;
+ public String authorName;
+ public List permissions;
+ public String privacyAgreementUrl;
+ public long apkPublishTime;
+ public long fileSize;
+ }
+
+ public static final DownloadConfirmListener DOWNLOAD_CONFIRM_LISTENER =
+ new DownloadConfirmListener() {
+
+ @Override
+ public void onDownloadConfirm(Activity context, int scenes, String infoUrl,
+ DownloadConfirmCallBack callBack) {
+ Log.d(TAG, "scenes:" + scenes + " info url:" + infoUrl);
+
+ //获取对应的json数据并自定义显示
+// DownloadApkConfirmDialog dialog = new DownloadApkConfirmDialog(context, getApkJsonInfoUrl(infoUrl), callBack);
+ DownloadApkConfirmDialog dialog = new DownloadApkConfirmDialog(context, infoUrl, callBack);//使用webview显示
+ if((scenes & ApkDownloadComplianceInterface.INSTALL_BITS) != 0){
+ dialog.setInstallTip();
+ scenes &= ~ApkDownloadComplianceInterface.INSTALL_BITS;
+ Log.d(TAG, "real scenes:" + scenes );
+ }
+ dialog.show();
+ }
+ };
+
+ public static String getApkJsonInfoUrl(String infoUrl) {
+ return infoUrl + JSON_INFO_PARAMETER;
+ }
+
+ public static ApkInfo getAppInfoFromJson(String jsonStr) {
+ ApkInfo result = null;
+
+ if (TextUtils.isEmpty(jsonStr)) {
+ Log.d(TAG, "请求应用信息返回值为空");
+ return null;
+ }
+ try {
+ JSONObject json = new JSONObject(jsonStr);
+ int retCode = json.optInt(JSON_RESULT_KEY, -1);
+ if (retCode != 0) {
+ Log.d(TAG, "请求应用信息返回值错误");
+ return null;
+ }
+ JSONObject dataJson = json.optJSONObject(JSON_DATA_KEY);
+ if (dataJson == null) {
+ Log.d(TAG, "请求应用信息返回值错误" + JSON_DATA_KEY);
+ return null;
+ }
+
+ if (dataJson != null) {
+ result = new ApkInfo();
+ result.iconUrl = dataJson.optString(ICON_URL_KEY);
+ result.appName = dataJson.optString(APP_NAME_KEY);
+ result.versionName = dataJson.optString(VERSION_NAME_KEY);
+ result.authorName = dataJson.optString(AUTHOR_NAME_KEY);
+ //这里获得是原始的权限数组,android.permission.ACCESS_NETWORK_STATE这种
+ JSONArray jsonPermissions = dataJson.optJSONArray(PERMISSIONS_KEY);
+ if (jsonPermissions != null) {
+ result.permissions = new ArrayList<>();
+ for (int i = 0; i < jsonPermissions.length(); i++) {
+ String rawPermission = jsonPermissions.getString(i);
+ if (USE_RAW_PERMISSIONS) {
+ result.permissions.add(jsonPermissions.getString(i));
+ continue;
+ }
+ //字面权限,不会显示所有,只会显示一部分常用权限
+ JSONObject permissionContent = PERMISSIONS_MAP_JSON.optJSONObject(rawPermission);
+ if (permissionContent != null) {
+ String permissionTitle = permissionContent.optString("title");
+ if (!TextUtils.isEmpty(permissionTitle)) {
+ result.permissions.add(permissionTitle);
+ }
+ }
+ }
+ }
+ result.privacyAgreementUrl = dataJson.optString(PRIVACY_AGREEMENT_KEY);
+ //后台返回的时间可能是秒也可能是毫秒,这里需要统一下为毫秒
+ //2000年1月1日1时0分0秒对应的 秒是946688401 毫秒是 946688401000
+ long publicTime = dataJson.optLong(UPDATE_TIME_KEY);
+ result.apkPublishTime = publicTime > 946688401000L ? publicTime : publicTime * 1000;
+ result.fileSize = dataJson.optLong(APK_FILE_SIZE_KEY);//单位是字节
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ return result;
+ }
+
+ /**
+ * 1. 权限对照表作为开发者参考使用
+ * 2. level = 1,代表敏感权限,0,代表普通权限,开发者可以按需使用
+ * 3. 权限未穷举部分,需要开发者自行翻译
+ */
+
+ public static final String PERMISSIONS_MAP_JSON_STR = "{\n" +
+ "\"android.permission.ACCESS_CHECKIN_PROPERTIES\": {\n" +
+ "\"desc\": \"允许应用对登记服务上传的属性拥有读/写权限。普通应用不应使用此权限。\",\n" +
+ "\"title\": \"访问检入属性\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.ACCESS_COARSE_LOCATION\": {\n" +
+ "\"desc\": \"允许该应用获取您的大致位置信息,这类位源信息来自于使用网络位置信息源(例如基站和WLAN)" +
+ "的位置信息服务。您必须在设备上开启这些位置信息服务,应用才能获得位置信息。应用会使用此类服务确定您的大概位置。\",\n" +
+ "\"title\": \"大致位置(基于网络)\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.ACCESS_LOCATION_EXTRA_COMMANDS\": {\n" +
+ "\"desc\": \"允许应用程序访问其他的位置信息提供程序命令。此权限使该应用可以干扰GPS或其他位置信息源的运作。\",\n" +
+ "\"title\": \"获取额外的位置信息提供程序命令。\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.ACCESS_NETWORK_STATE\": {\n" +
+ "\"desc\": \"允许该应用查看网络连接的相关信息,例如存在和连接的网络。\",\n" +
+ "\"title\": \"查看网络连接。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.ACCESS_NOTIFICATION_POLICY\": {\n" +
+ "\"desc\": \"允许访问通知策略的应用程序的标记权限。\",\n" +
+ "\"title\": \"访问通知策略\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.ACCESS_WIFI_STATE\": {\n" +
+ "\"desc\": \"允许该应用查看WLAN网络的相关信息。例如是否启用了WLAN以及连接的WLAN设备的名称。\",\n" +
+ "\"title\": \"查看WLAN连接\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.ACCOUNT_MANAGER\": {\n" +
+ "\"desc\": \"允许应用使用AccountManager的帐户身份验证程序功能,包括创建帐户以及获取和设置复密码。\",\n" +
+ "\"title\": \"创建帐户并设置密码\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.ACTIVITY_RECOGNITION\": {\n" +
+ "\"desc\": \"允许应用程序识别身体活动。\",\n" +
+ "\"title\": \"识别身体活动\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.ANSWER_PHONE_CALLS\": {\n" +
+ "\"desc\": \"允许该应用接听来电。\",\n" +
+ "\"title\": \"接听来电\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.BATTERY_STATS\": {\n" +
+ "\"desc\": \"允许应用读取当前电量使用情况的基础数据。此权限可让应用了解关于您使用了哪些应用的详细信息。\",\n" +
+ "\"title\": \"读取电池使用统计信息。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.BIND_CARRIER_SERVICES\": {\n" +
+ "\"desc\": \"允许应用告知系统哪些小部件可提供哪个应用使用。拥有此权限的应用可向其他应用授予对个人数据的访问权限。普通应用不应使用此权限。\",\n" +
+ "\"title\": \"选择小部件\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.BIND_CONTROLS\": {\n" +
+ "\"desc\": \"允许SystemUI请求第三方控件。\",\n" +
+ "\"title\": \"请求第三方控件\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.BIND_QUICK_SETTINGS_TILE\": {\n" +
+ "\"desc\": \"允许应用程序绑定到第三方快速设置磁贴。\",\n" +
+ "\"title\": \"绑定快速设置磁贴\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.BLUETOOTH\": {\n" +
+ "\"desc\": \"允许该应用查看手机上的蓝牙配置,以及建立和接受与配对设备的连接。\",\n" +
+ "\"title\": \"与蓝牙设备配对。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.BLUETOOTH_ADMIN\": {\n" +
+ "\"desc\": \"允许应用配置本地蓝牙手机,以及发现远程设备并进行配对。\",\n" +
+ "\"title\": \"访问蓝牙设置。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.BLUETOOTH_PRIVILEGED\": {\n" +
+ "\"desc\": \"允许应用程序与蓝牙设备配对,而无需用户交互。\",\n" +
+ "\"title\": \"运行应用进行蓝牙配对。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.BODY_SENSORS\": {\n" +
+ "\"desc\": \"允许应用访问您用于测量身体状况(如心跳速率)的传感器中的数据。\",\n" +
+ "\"title\": \"人体传感器\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.BROADCAST_PACKAGE_REMOVED\": {\n" +
+ "\"desc\": \"允许应用程序广播已删除应用程序的通知。\",\n" +
+ "\"title\": \"发送软件包被移除的广播通知。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.BROADCAST_SMS\": {\n" +
+ "\"desc\": \"允许应用广播一条有关已收到短信的通知。恶意应用可能借此伪造接到的短信。\",\n" +
+ "\"title\": \"发送短信收到的广播\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.BROADCAST_STICKY\": {\n" +
+ "\"desc\": \"允许应用程序广播粘性意图。\",\n" +
+ "\"title\": \"发送持久广播。\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.BROADCAST_WAP_PUSH\": {\n" +
+ "\"desc\": \"允许应用程序广播WAP PUSH接收通知。\",\n" +
+ "\"title\": \"发送WAP-PUSH 收到的广播。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.CALL_COMPANION_APP\": {\n" +
+ "\"desc\": \"允许应用作为呼叫伴随应用启用。\",\n" +
+ "\"title\": \"伴随呼叫启动\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.CALL_PHONE\": {\n" +
+ "\"desc\": \"允许应用程序在不通过拨号界面的情况下发起电话呼叫。\",\n" +
+ "\"title\": \"直接拨打电话号码\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.CALL_PRIVILEGED\": {\n" +
+ "\"desc\": \"允许应用程序拨打任何电话号码,包括紧急号码,而无需通过拨号界面来让用户确认正在拨打的电话。\",\n" +
+ "\"title\": \"直接呼叫任何电话号码\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.CAMERA\": {\n" +
+ "\"desc\": \"允许该应用使用相机拍摄照片和视频。此权限可让该应用随时使用相机,而无需您的确认。\",\n" +
+ "\"title\": \"拍摄照片和视频\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.CAPTURE_AUDIO_OUTPUT\": {\n" +
+ "\"desc\": \"允许该应用捕获和重定向音频输出。\",\n" +
+ "\"title\": \"捕获音频输出。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.CHANGE_COMPONENT_ENABLED_STATE\": {\n" +
+ "\"desc\": \"允许应用启用或停用其他应用的组件。\",\n" +
+ "\"title\": \"启用或停用应用组件\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.CHANGE_CONFIGURATION\": {\n" +
+ "\"desc\": \"允许应用程序修改当前设备配置。\",\n" +
+ "\"title\": \"更改系统显示设置。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.CHANGE_NETWORK_STATE\": {\n" +
+ "\"desc\": \"允许应用程序更改网络连接状态。\",\n" +
+ "\"title\": \"更改网络连接状态。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.CHANGE_WIFI_MULTICAST_STATE\": {\n" +
+ "\"desc\": \"允许该应用使用多播地址接收发送到WLAN网络上所有设备的数据包。该操作的耗电量比非多播模式更大。\",\n" +
+ "\"title\": \"允许接收WLAN多播。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.CHANGE_WIFI_STATE\": {\n" +
+ "\"desc\": \"允许该应用与 WLAN 接入点建立和断开连接,以及更改WLAN网络的设备配置。\",\n" +
+ "\"title\": \"连接WLAN网络和断开连接。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.CLEAR_APP_CACHE\": {\n" +
+ "\"desc\": \"允许应用程序清除设备上所有已安装应用程序的缓存。\",\n" +
+ "\"title\": \"删除所有应用缓存数据\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.CONTROL_LOCATION_UPDATES\": {\n" +
+ "\"desc\": \"允许应用启用/停止来自无线装置的位置更新通知。普通应用应该使用此权限。\",\n" +
+ "\"title\": \"控制位置更新通知。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.DELETE_CACHE_FILES\": {\n" +
+ "\"desc\": \"允许删除应用程序的缓存文件。\",\n" +
+ "\"title\": \"删除其他应用程序的缓存文件。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.DELETE_PACKAGES\": {\n" +
+ "\"desc\": \"允许应用程序删除其他应用。\",\n" +
+ "\"title\": \"删除应用\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.DIAGNOSTIC\": {\n" +
+ "\"desc\": \"允许应用读取/写入诊断拥有的所有资源(例如/dev中的文件)。这可能会影响系统的稳定性和安全性。\",\n" +
+ "\"title\": \"允许应用程序读写诊断资源。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.DISABLE_KEYGUARD\": {\n" +
+ "\"desc\": \"允许该应用停用键锁以及任何关联的密码安全措施。例如,让手机在接听来电时停用键锁,在通话结束后重新启用键。\",\n" +
+ "\"title\": \"停用屏幕锁定\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.DUMP\": {\n" +
+ "\"desc\": \"允许应用程序从系统服务中检索状态转储信息。\",\n" +
+ "\"title\": \"检索系统内部状态\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.EXPAND_STATUS_BAR\": {\n" +
+ "\"desc\": \"允许应用程序展开或折叠状态栏。\",\n" +
+ "\"title\": \"展开/收拢状态栏\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.FACTORY_TEST\": {\n" +
+ "\"desc\": \"允许应用以制造商测试应用程序的身份运行,以root用户身份运行。\",\n" +
+ "\"title\": \"在出厂测试模式下运行\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.FOREGROUND_SERVICE\": {\n" +
+ "\"desc\": \"允许应用程序使用前台服务。\",\n" +
+ "\"title\": \"使用前台服务\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.GET_ACCOUNTS\": {\n" +
+ "\"desc\": \"允许访问帐户服务中的帐户列表。\",\n" +
+ "\"title\": \"查找设备上的账户\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.GET_ACCOUNTS_PRIVILEGED\": {\n" +
+ "\"desc\": \"允许访问帐户服务中的帐户列表。\",\n" +
+ "\"title\": \"访问账户列表\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.GET_PACKAGE_SIZE\": {\n" +
+ "\"desc\": \"允许应用程序查看其他应用使用的空间大小。\",\n" +
+ "\"title\": \"计算应用存储空间\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.GET_TASKS\": {\n" +
+ "\"desc\": \"允许应用程序获取当前的信息或最近运行的任务。\",\n" +
+ "\"title\": \"检索正在运行的应用。\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.INSTALL_LOCATION_PROVIDER\": {\n" +
+ "\"desc\": \"创建用于测试的模拟位置源或安装新的位置提供程序。\",\n" +
+ "\"title\": \"允许安装位置信息提供程序\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.INSTALL_PACKAGES\": {\n" +
+ "\"desc\": \"允许应用程序安装其他应用。\",\n" +
+ "\"title\": \"直接安装应用\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.INSTANT_APP_FOREGROUND_SERVICE\": {\n" +
+ "\"desc\": \"允许即时应用创建前台服务。\",\n" +
+ "\"title\": \"创建前台服务\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.INTERNET\": {\n" +
+ "\"desc\": \"允许该应用创建网络套接字和使用自定义网络协议。浏览器和其他某些应用提供了向互联网发送数据的途径,因此应用无需该权限即可向互联网发送数据。\",\n" +
+ "\"title\": \"完全的网络访问权限\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.KILL_BACKGROUND_PROCESSES\": {\n" +
+ "\"desc\": \"允许应用清理后台应用进程。\",\n" +
+ "\"title\": \"关闭其他应用\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.LOADER_USAGE_STATS\": {\n" +
+ "\"desc\": \"允许数据加载器读取程序包的访问日志。\",\n" +
+ "\"title\": \"允许读取程序包日志\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.MANAGE_DOCUMENTS\": {\n" +
+ "\"desc\": \"允许应用程序管理档存储空间。\",\n" +
+ "\"title\": \"管理文档存储空间\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.MANAGE_EXTERNAL_STORAGE\": {\n" +
+ "\"desc\": \"允许应用程序访问作用域存储中的外部存储。\",\n" +
+ "\"title\": \"允许程序访问APP通知方式\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.MEDIA_CONTENT_CONTROL\": {\n" +
+ "\"desc\": \"允许应用控制媒体播放及使用媒体信息(标题、作者..)。\",\n" +
+ "\"title\": \"控制媒体播放和使用元数据。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.MODIFY_AUDIO_SETTINGS\": {\n" +
+ "\"desc\": \"允许该应用修改全局音频设置,例如音量和用于输出的扬声器。\",\n" +
+ "\"title\": \"更改您的音频设置\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.MODIFY_PHONE_STATE\": {\n" +
+ "\"desc\": \"允许应用控制设备的电话功能。拥有此权限的应用可在不通知您的情况下执行切换网络、开关手机无线装置等此类操。\",\n" +
+ "\"title\": \"修改手机状态\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.MOUNT_FORMAT_FILESYSTEMS\": {\n" +
+ "\"desc\": \"允许格式化可移动存储设备。\",\n" +
+ "\"title\": \"清除USB存储设备内容\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\": {\n" +
+ "\"desc\": \"允许挂载和卸载可移动存储的文件系统。\",\n" +
+ "\"title\": \"访问USB存储设备的文件系统\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.NFC\": {\n" +
+ "\"desc\": \"允许应用与近距离无线通信(NFC)标签、卡和读取器通信。\",\n" +
+ "\"title\": \"控制近距离通信\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.PACKAGE_USAGE_STATS\": {\n" +
+ "\"desc\": \"允许应用收集组件使用情况统计信息。\",\n" +
+ "\"title\": \"更新组件使用情况统计\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.PERSISTENT_ACTIVITY\": {\n" +
+ "\"desc\": \"允许应用程序在内存中持续保留其自身的某些组件。\",\n" +
+ "\"title\": \"让应用始终运行\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.PROCESS_OUTGOING_CALLS\": {\n" +
+ "\"desc\": \"允许应用在拨出电话时查看拨打的电话号码,并选择改为拨打其他号码或完全中止通话。\",\n" +
+ "\"title\": \"重新设置外拨电话的路径\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.QUERY_ALL_PACKAGES\": {\n" +
+ "\"desc\": \"允许查询设备上的任何应用程序。\",\n" +
+ "\"title\": \"查看设备上所有应用\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.READ_CALENDAR\": {\n" +
+ "\"desc\": \"允许应用读取用户的日历数据。\",\n" +
+ "\"title\": \"读取日历活动信息\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.READ_CALL_LOG\": {\n" +
+ "\"desc\": \"允许应用程序读取用户的通话记录。\",\n" +
+ "\"title\": \"读取通话记录\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.READ_CONTACTS\": {\n" +
+ "\"desc\": \"允许该应用读取您手机上存储的联系人的相关数据,包括您通过打电话、发送电子邮件或以其他方式与特定个人通信的频率。\",\n" +
+ "\"title\": \"读取您的通讯录\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.READ_EXTERNAL_STORAGE\": {\n" +
+ "\"desc\": \"允许应用程序从外部存储读取数据。\",\n" +
+ "\"title\": \"读取您的USB存储设备中的内容\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.READ_LOGS\": {\n" +
+ "\"desc\": \"允许应用程序读取系统日志文件。\",\n" +
+ "\"title\": \"查阅敏感日志数据\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.READ_PHONE_NUMBERS\": {\n" +
+ "\"desc\": \"允许读取访问设备的电话号码。\",\n" +
+ "\"title\": \"读取手机电话号码\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.READ_PHONE_STATE\": {\n" +
+ "\"desc\": \"允许该应用访问设备的电话功能,此权限可以让应用确定本机号码和设备ID、是否正处于通话状态以及拨打的号码。\",\n" +
+ "\"title\": \"读取手机状态和身份\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.READ_PRECISE_PHONE_STATE\": {\n" +
+ "\"desc\": \"允许访问精确的电话状态。\",\n" +
+ "\"title\": \"读取确切的手机状态\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.READ_SMS\": {\n" +
+ "\"desc\": \"允许该应用读取您手机或SIM卡上存储的短信。\",\n" +
+ "\"title\": \"读取您的讯息(短信或彩信)\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.READ_SYNC_SETTINGS\": {\n" +
+ "\"desc\": \"许该应用读取某个账户的同步设置。\",\n" +
+ "\"title\": \"读取同步设置。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.READ_SYNC_STATS\": {\n" +
+ "\"desc\": \"允许该应用读取某个账户的同步统计信息,包括同步活动历史记录和同步数据量。\",\n" +
+ "\"title\": \"读取同步统计信息。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.REBOOT\": {\n" +
+ "\"desc\": \"允许应用强行重新启动设备。\",\n" +
+ "\"title\": \"强行重新启动手机。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.RECEIVE_BOOT_COMPLETED\": {\n" +
+ "\"desc\": \"允许应用在系统完成引导后立即自动启动。\",\n" +
+ "\"title\": \"开机启动\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.RECEIVE_MMS\": {\n" +
+ "\"desc\": \"允许应用程序监听彩信消息。\",\n" +
+ "\"title\": \"接收讯息(彩信)\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.RECEIVE_SMS\": {\n" +
+ "\"desc\": \"允许应用程序接收短信消息。\",\n" +
+ "\"title\": \"接收讯息(短信)\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.RECEIVE_WAP_PUSH\": {\n" +
+ "\"desc\": \"允许应用程序接收WAP推送消息。\",\n" +
+ "\"title\": \"接收讯息(WAP)\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.RECORD_AUDIO\": {\n" +
+ "\"desc\": \"允许应用程序录制音频。\",\n" +
+ "\"title\": \"录音\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.REORDER_TASKS\": {\n" +
+ "\"desc\": \"允允许该应用将任务移动到前台和后台。\",\n" +
+ "\"title\": \"对正在运行的应用重新排序\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND\": {\n" +
+ "\"desc\": \"允许合作应用在后台运行。\",\n" +
+ "\"title\": \"合作应用后台运行\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND\": {\n" +
+ "\"desc\": \"允许合作应用在后台使用数据。\",\n" +
+ "\"title\": \"合作应用后台使用数据\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.REQUEST_DELETE_PACKAGES\": {\n" +
+ "\"desc\": \"允许应用程序请求卸载其他应用。\",\n" +
+ "\"title\": \"卸载其他应用\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS\": {\n" +
+ "\"desc\": \"允许用户请求应用忽略电池优化。\",\n" +
+ "\"title\": \"忽略电池优化\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.REQUEST_INSTALL_PACKAGES\": {\n" +
+ "\"desc\": \"允许应用程序请求安装软件包。\",\n" +
+ "\"title\": \"安装软件\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.REQUEST_PASSWORD_COMPLEXITY\": {\n" +
+ "\"desc\": \"允许应用程序请求屏幕锁定复杂性,并提示用户将屏幕锁定更新到特定的复杂性级别。\",\n" +
+ "\"title\": \"获取屏幕锁定复杂性\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.RESTART_PACKAGES\": {\n" +
+ "\"desc\": \"允许应用程序结束其他应用的后台进程。\",\n" +
+ "\"title\": \"关闭其他应用\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.SEND_RESPOND_VIA_MESSAGE\": {\n" +
+ "\"desc\": \"允许应用程序将请求发送到其他应用程序,以便处理来电的“通过信息回复”事件。\",\n" +
+ "\"title\": \"发送“通过信息回复”事件\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.SEND_SMS\": {\n" +
+ "\"desc\": \"允许应用程序发送短信消息。\",\n" +
+ "\"title\": \"发送短信\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.SET_ANIMATION_SCALE\": {\n" +
+ "\"desc\": \"允许修改全局动画缩放比例。\",\n" +
+ "\"title\": \"修改全局动画\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.SET_DEBUG_APP\": {\n" +
+ "\"desc\": \"允许该应用对其他应用程序进行调试。\",\n" +
+ "\"title\": \"启动应用调试\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.SET_PREFERRED_APPLICATIONS\": {\n" +
+ "\"desc\": \"允许程序修改您的首选应用。\",\n" +
+ "\"title\": \"设置首选应用。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.SET_PROCESS_LIMIT\": {\n" +
+ "\"desc\": \"允许应用程序设置可以运行的应用程序进程的最大数量。\",\n" +
+ "\"title\": \"限制运行的进程数量。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.SET_TIME\": {\n" +
+ "\"desc\": \"允许应用程序直接设置系统时间。\",\n" +
+ "\"title\": \"设置时间。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.SET_TIME_ZONE\": {\n" +
+ "\"desc\": \"允许应用程序直接设置系统时区。\",\n" +
+ "\"title\": \"设置时区\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.SET_WALLPAPER\": {\n" +
+ "\"desc\": \"允许应用程序设置墙纸。\",\n" +
+ "\"title\": \"设置壁纸\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.SET_WALLPAPER_HINTS\": {\n" +
+ "\"desc\": \" 允许应用程序设置墙纸大小的提示。\",\n" +
+ "\"title\": \"调整您的壁纸大小\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.SIGNAL_PERSISTENT_PROCESSES\": {\n" +
+ "\"desc\": \"允许应用程序请求将信号发送到所有持久性进程。\",\n" +
+ "\"title\": \"向应用发送 Linux 信号\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.SMS_FINANCIAL_TRANSACTIONS\": {\n" +
+ "\"desc\": \"允许金融应用读取过滤的短信。\",\n" +
+ "\"title\": \"读取过滤短信\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.START_VIEW_PERMISSION_USAGE\": {\n" +
+ "\"desc\": \"允许启动应用程序的权限使用屏幕。\",\n" +
+ "\"title\": \"使用手机屏幕\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.STATUS_BAR\": {\n" +
+ "\"desc\": \"允许应用程序打开,关闭或禁用状态栏及其图标。\",\n" +
+ "\"title\": \"停用或修改状态栏\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.SYSTEM_ALERT_WINDOW\": {\n" +
+ "\"desc\": \"允许应用显示在所有其他应用的顶部。\",\n" +
+ "\"title\": \"在其他应用之上显示内容\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.TRANSMIT_IR\": {\n" +
+ "\"desc\": \"允许使用设备的红外发射器。\",\n" +
+ "\"title\": \"使用红外线发射器\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.UPDATE_DEVICE_STATS\": {\n" +
+ "\"desc\": \"允许应用程序更新设备统计信息。\",\n" +
+ "\"title\": \"修改使用统计信息。\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.USE_BIOMETRIC\": {\n" +
+ "\"desc\": \"允许应用使用设备支持的生物特征识别方式。\",\n" +
+ "\"title\": \"允许使用指纹等识别方式\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.USE_FINGERPRINT\": {\n" +
+ "\"desc\": \"允许应用使用指纹硬件。\",\n" +
+ "\"title\": \"允许应用使用指纹硬件\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.USE_FULL_SCREEN_INTENT\": {\n" +
+ "\"desc\": \"允许应用显示全屏通知。\",\n" +
+ "\"title\": \"允许应用显示全屏通知\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.USE_SIP\": {\n" +
+ "\"desc\": \"允许应用程序使用SIP服务。\",\n" +
+ "\"title\": \"拨打/接听SIP电话\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.VIBRATE\": {\n" +
+ "\"desc\": \"允许使用振动器。\",\n" +
+ "\"title\": \"控制振动\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.WAKE_LOCK\": {\n" +
+ "\"desc\": \"允许应用阻止手机进入休眠状态。\",\n" +
+ "\"title\": \"防止手机休眠\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.WRITE_APN_SETTINGS\": {\n" +
+ "\"desc\": \"允许应用更改网络设置,并拦截和检查所有网络流量。\",\n" +
+ "\"title\": \"更改/拦截网络设置和流量\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.WRITE_CALENDAR\": {\n" +
+ "\"desc\": \"允许应用程序写入、删除、更改用户的日历数据。\",\n" +
+ "\"title\": \"添加或修改日历活动,并在所有者不知情的情况下向邀请对象发送电子邮件\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.WRITE_CALL_LOG\": {\n" +
+ "\"desc\": \"允许应用程序添加/修改用户的通话记录。\",\n" +
+ "\"title\": \"写入通话记录\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.WRITE_CONTACTS\": {\n" +
+ "\"desc\": \"允许应用程序写入用户的联系人数据。\",\n" +
+ "\"title\": \"修改您的通讯录\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.WRITE_EXTERNAL_STORAGE\": {\n" +
+ "\"desc\": \"允许应用程序读取/写入外部存储。\",\n" +
+ "\"title\": \"修改或删除您的USB存储设备中的内容\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.WRITE_SECURE_SETTINGS\": {\n" +
+ "\"desc\": \"允许应用读取或写入安全系统设置。\",\n" +
+ "\"title\": \"修改安全系统设置\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.WRITE_SETTINGS\": {\n" +
+ "\"desc\": \"允许应用读取或写入系统设置。\",\n" +
+ "\"title\": \"修改系统设置\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.WRITE_SYNC_SETTINGS\": {\n" +
+ "\"desc\": \"允许应用程序修改某个账户的同步设置。\",\n" +
+ "\"title\": \"启用和停用同步\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.WRITE_VOICEMAIL\": {\n" +
+ "\"desc\": \"允许应用程序修改和删除系统中现有的语音邮件。\",\n" +
+ "\"title\": \"读取修改语音邮件\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.DOWNLOAD_WITHOUT_NOTIFICATION\": {\n" +
+ "\"desc\": \"允许该应用通过下载管理器下载文件,而不会向用户显示任何通知。\",\n" +
+ "\"title\": \"直接下载文件而不显示通知\",\n" +
+ "\"level\": 1\n" +
+ "},\n" +
+ "\"android.permission.ACCESS_ALL_EXTERNAL_STORAGE\": {\n" +
+ "\"desc\": \"允许该应用访问所有用户的外部存储。\",\n" +
+ "\"title\": \"访问所有用户的外部存储设备\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.ASEC_ACCESS\": {\n" +
+ "\"desc\": \"允许该应用获取有关内部存储的信息。\",\n" +
+ "\"title\": \"获取有关内部存储设备的信息\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.ACCESS_MOCK_LOCATION\": {\n" +
+ "\"desc\": \"允许模拟位置源进行测试。\",\n" +
+ "\"title\": \"停用模拟地点来源进行测试\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"android.permission.AUTHENTICATE_ACCOUNTS\": {\n" +
+ "\"desc\": \"允许创建帐户并设置密码。\",\n" +
+ "\"title\": \"创建账户并设置密码\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"com.android.alarm.permission.SET_ALARM\": {\n" +
+ "\"desc\": \"允许应用程序为用户设置闹钟。\",\n" +
+ "\"title\": \"设置闹钟\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"com.android.voicemail.permission.READ_VOICEMAIL\": {\n" +
+ "\"desc\": \"允许应用程序读取系统中的语音邮件。\",\n" +
+ "\"title\": \"读取语言邮件\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"com.android.launcher.permission.INSTALL_SHORTCUT\": {\n" +
+ "\"desc\": \"允许应用程序在桌面中创建快捷方式。\",\n" +
+ "\"title\": \"安装快捷方式\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"com.android.launcher.permission.UNINSTALL_SHORTCUT\": {\n" +
+ "\"desc\": \"允许删除快捷方式。\",\n" +
+ "\"title\": \"卸载快捷方式\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"com.android.voicemail.permission.ADD_VOICEMAIL\": {\n" +
+ "\"desc\": \"允许该应用向您的语音信箱中添加邮件。\",\n" +
+ "\"title\": \"添加语音邮件\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"com.android.email.permission.READ_ATTACHMENT\": {\n" +
+ "\"desc\": \"允许该应用读取您的电子邮件附件。\",\n" +
+ "\"title\": \"读取电子邮件附件\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"com.android.browser.permission.WRITE_HISTORY_BOOKMARKS\": {\n" +
+ "\"desc\": \"允许该应用修改浏览器的历史记录或手机上存储的书签。\",\n" +
+ "\"title\": \"写入网络书签和历史记录\",\n" +
+ "\"level\": 0\n" +
+ "},\n" +
+ "\"com.android.browser.permission.READ_HISTORY_BOOKMARKS\": {\n" +
+ "\"desc\": \"允许该应用读取浏览器访问过的所有URL的历史记录,以及浏览器的所有书签的历史记录。\",\n" +
+ "\"title\": \"读取您的网络书签和历史记录\",\n" +
+ "\"level\": 0\n" +
+ "}\n" +
+ "}";
+
+ static {
+ try {
+ PERMISSIONS_MAP_JSON = new JSONObject(PERMISSIONS_MAP_JSON_STR);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/LogUtil.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/LogUtil.kt
new file mode 100644
index 0000000..12ace42
--- /dev/null
+++ b/android/src/main/kotlin/com/example/union_ad_ssgf/LogUtil.kt
@@ -0,0 +1,136 @@
+package com.example.union_ad_ssgf;
+
+import android.text.TextUtils
+import android.util.Log
+
+
+/**
+ * @Description: 打印工具类
+ * 可自动把调用位置所在的类名和方法名作为tag,并可设置打印级别Ï
+ */
+object LogUtil {
+ // 以下为打印级别,级别从低到高
+ const val LOG_LEVEL_VERBOSE = 1
+ const val LOG_LEVEL_DEBUG = 2
+ const val LOG_LEVEL_INFO = 3
+ const val LOG_LEVEL_WARN = 4
+ const val LOG_LEVEL_ERROR = 5
+ const val LOG_LEVEL_NOLOG = 6
+ private var AppName = ""
+ private var PrintLine = false
+ private var LogLevel = LOG_LEVEL_VERBOSE
+ private var isShow = false
+
+ /**
+ * 可在打印的TAG前添加应用名标识,不设置则不输出
+ */
+ fun setAppName(appName: String) {
+ AppName = appName
+ }
+
+ /**
+ * 是否输出打印所在的行数,默认不输出
+ */
+ fun setPrintLine(enable: Boolean) {
+ PrintLine = enable
+ }
+
+ /**
+ * 可在打印的TAG前添加应用名标识,不设置则不输出
+ */
+ fun setShow(show: Boolean) {
+ isShow = show
+ }
+
+
+ /**
+ * 设置打印级别,且只有等于或高于该级别的打印才会输出
+ */
+ fun setLogLevel(logLevel: Int) {
+ LogLevel = logLevel
+ }
+
+ fun v() {
+ log(LOG_LEVEL_VERBOSE, "")
+ }
+
+ fun d() {
+ log(LOG_LEVEL_DEBUG, "")
+ }
+
+ fun i() {
+ log(LOG_LEVEL_INFO, "")
+ }
+
+ fun w() {
+ log(LOG_LEVEL_WARN, "")
+ }
+
+ fun e() {
+ log(LOG_LEVEL_ERROR, "")
+ }
+
+ fun v(msg: String) {
+ if (LogLevel <= LOG_LEVEL_VERBOSE) {
+ log(LOG_LEVEL_VERBOSE, msg)
+ }
+ }
+
+ fun d(msg: String) {
+ if (LogLevel <= LOG_LEVEL_DEBUG) {
+ log(LOG_LEVEL_DEBUG, msg)
+ }
+ }
+
+ fun i(msg: String) {
+ if (LogLevel <= LOG_LEVEL_INFO) {
+ log(LOG_LEVEL_INFO, msg)
+ }
+ }
+
+ fun w(msg: String) {
+ if (LogLevel <= LOG_LEVEL_WARN) {
+ log(LOG_LEVEL_WARN, msg)
+ }
+ }
+
+ fun e(msg: String) {
+ if (LogLevel <= LOG_LEVEL_ERROR) {
+ log(LOG_LEVEL_ERROR, msg)
+ }
+ }
+
+ private fun log(logLevel: Int, msg: String) {
+ if(!isShow){
+ return
+ }
+ val caller = Thread.currentThread().stackTrace[4]
+ var callerClazzName = caller.className
+ if (callerClazzName.contains(".")) {
+ callerClazzName = callerClazzName.substring(callerClazzName.lastIndexOf(".") + 1)
+ }
+ if (callerClazzName.contains("$")) {
+ callerClazzName = callerClazzName.substring(0, callerClazzName.indexOf("$"))
+ }
+ var tag = callerClazzName
+ if (!TextUtils.isEmpty(AppName)) {
+ tag = AppName + "_" + tag
+ }
+ if (PrintLine) {
+ tag += "(Line:%d)"
+ tag = String.format(tag, caller.lineNumber)
+ }
+ tag = String.format(tag, callerClazzName)
+ val message = "---" + caller.methodName + "---" + msg
+ when (logLevel) {
+ LOG_LEVEL_VERBOSE -> Log.v(tag, message)
+ LOG_LEVEL_DEBUG -> Log.d(tag, message)
+ LOG_LEVEL_INFO -> Log.i(tag, message)
+ LOG_LEVEL_WARN -> Log.w(tag, message)
+ LOG_LEVEL_ERROR -> Log.e(tag, message)
+ LOG_LEVEL_NOLOG -> {
+ }
+ }
+ }
+}
+
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/PluginDelegate.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/PluginDelegate.kt
deleted file mode 100644
index 460abb4..0000000
--- a/android/src/main/kotlin/com/example/union_ad_ssgf/PluginDelegate.kt
+++ /dev/null
@@ -1,183 +0,0 @@
-package com.example.union_ad_ssgf
-
-import android.annotation.SuppressLint
-import android.app.Activity
-import android.content.Intent
-import android.util.Log
-import com.example.union_ad_ssgf.config.UnionADConfig
-import com.example.union_ad_ssgf.page.AdSplashActivity
-import com.example.union_ad_ssgf.page.RewardVideoPage
-import com.qq.e.comm.managers.GDTAdSdk
-import com.qq.e.comm.managers.setting.GlobalSetting.setPersonalizedState
-import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding
-import io.flutter.plugin.common.EventChannel
-import io.flutter.plugin.common.EventChannel.EventSink
-import io.flutter.plugin.common.MethodCall
-import io.flutter.plugin.common.MethodChannel
-
-
-/**
- * 插件代理中心
- *
- * @param activity 当前 Activity
- * @param bind Flutter 插件绑定对象
- */
-class PluginDelegate(var activity: Activity, bind: FlutterPluginBinding) :
- MethodChannel.MethodCallHandler, EventChannel.StreamHandler {
- private val s = PluginDelegate::class.java.getSimpleName();
-
- // 事件通道
- private var eventSink: EventSink? = null
-
- /**
- * 初始化代码块
- */
- init {
- _instance = this
- }
-
- companion object {
- /**
- * 插件代理对象
- */
- @SuppressLint("StaticFieldLeak")
- private lateinit var _instance: PluginDelegate
- fun getInstance(): PluginDelegate {
- return _instance
- }
- }
-
- override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
- val method = call.method
- Log.d(s, "MethodChannel onMethodCall method:" + method + " arguments:" + call.arguments)
- when (method) {
- /**
- * 获取当前版本
- */
- "getPlatformVersion" -> {
- getPlatformVersion(call, result)
- }
- /**
- * 初始化
- */
- "initAd" -> {
- initAd(call, result)
- }
- /**
- * 设置广告个性化
- */
- "setPersonalizedState" -> {
- setPersonalizedState(call, result)
- }
- /**
- * 开屏广告
- */
- "showSplashAd" -> {
- showSplashAd(call, result)
- }
- /**
- * 激励广告
- */
- "showRewardVideoAd" -> {
- showRewardVideoAd(call, result);
- }
- /**
- * 错误桥接
- */
- else -> {
- result.notImplemented()
- }
- }
- }
-
- override fun onListen(arguments: Any, events: EventChannel.EventSink) {
- Log.d(s, "EventChannel onListen arguments:$arguments")
- eventSink = events
- }
-
- /**
- * 取消事件通道监听
- * @param arguments 参数
- */
- override fun onCancel(arguments: Any?) {
- Log.d(s, "EventChannel onCancel")
- eventSink = null
- }
-
- /**
- * 获取当前版本
- * @param call MethodCall
- * @param result Result
- */
- private fun getPlatformVersion(call: MethodCall, result: MethodChannel.Result) {
- result.success(" Union AD Android " + android.os.Build.VERSION.RELEASE);
- }
-
- /**
- * 初始化广告
- * @param call MethodCall
- * @param result Result
- */
- private fun initAd(call: MethodCall, result: MethodChannel.Result) {
- val appId = call.argument("appId")
- /**
- * 该接口不会采集用户信息
- */
- GDTAdSdk.initWithoutStart(activity.applicationContext, appId)
- /**
- * 调用initWithoutStart后请尽快调用start,否则可能影响广告填充,造成收入下降
- */
- GDTAdSdk.start(object : GDTAdSdk.OnStartListener {
- /**
- * 推荐开发者在 onStartSuccess 回调后开始拉广告
- */
- override fun onStartSuccess() {
- Log.e("gdt onStartSuccess", "加载成功")
- }
- override fun onStartFailed(e: Exception) {
- Log.e("gdt onStartFailed:", e.toString())
- }
- })
- result.success(true)
- }
-
- /**
- * 设置广告个性化
- * @param call MethodCall
- * @param result Result
- */
- private fun setPersonalizedState(call: MethodCall, result: MethodChannel.Result) {
- val state = call.argument("state")!!
- setPersonalizedState(state)
- result.success(true);
- }
-
- /**
- * 开屏广告
- * @param call MethodCall
- * @param result Result
- */
- private fun showSplashAd(call: MethodCall, result: MethodChannel.Result) {
- val posId: String? = call.argument(UnionADConfig.KEY_POSID)
- val logo: String? = call.argument(UnionADConfig.KEY_LOGO)
- val fetchDelay: Double = call.argument(UnionADConfig.KEY_FETCH_DELAY)!!
- val intent = Intent(activity, AdSplashActivity::class.java)
- intent.putExtra(UnionADConfig.KEY_POSID, posId)
- intent.putExtra(UnionADConfig.KEY_LOGO, logo)
- intent.putExtra(UnionADConfig.KEY_FETCH_DELAY, fetchDelay)
- activity.startActivity(intent)
- result.success(true)
- }
-
- /**
- * 显示激励视频广告
- * @param call MethodCall
- * @param result Result
- */
- private fun showRewardVideoAd(call: MethodCall, result: MethodChannel.Result) {
- val iad = RewardVideoPage()
- iad.showAd(activity, 1, call)
- result.success(true)
- }
-
-}
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/UIUtils.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/UIUtils.kt
new file mode 100644
index 0000000..aa699f4
--- /dev/null
+++ b/android/src/main/kotlin/com/example/union_ad_ssgf/UIUtils.kt
@@ -0,0 +1,249 @@
+package com.example.union_ad_ssgf;
+
+import android.app.Activity
+import android.content.Context
+import android.os.Build
+import android.util.DisplayMetrics
+import android.view.View
+import android.view.WindowManager
+import java.lang.reflect.InvocationTargetException
+
+object UIUtils {
+
+ fun getScreenWidth(context: Context): Int {
+ return context.resources.displayMetrics.widthPixels
+ }
+
+ fun getScreenHeight(context: Context): Int {
+ return getRealHeight(context)
+ }
+
+ fun getScreenWidthDp(context: Context): Float {
+ val scale = context.resources.displayMetrics.density.toFloat()
+ val width = context.resources.displayMetrics.widthPixels.toFloat()
+ val num = if (scale <= 0) 1f else scale
+ return width / num + 0.5f
+ }
+
+ //全面屏、刘海屏适配
+ fun getHeightDp(activity: Activity): Float {
+ hideBottomUIMenu(activity)
+ val height: Float
+ val realHeight = getRealHeight(activity)
+ height = if (hasNotchScreen(activity)) {
+ px2dip(activity, realHeight - getStatusBarHeight(activity))
+ } else {
+ px2dip(activity, realHeight.toFloat())
+ }
+ return height
+ }
+
+ fun hideBottomUIMenu(activity: Activity?) {
+ if (activity == null) {
+ return
+ }
+ try {
+ //隐藏虚拟按键,并且全屏
+ if (Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) { // lower api
+ val v = activity.window.decorView
+ v.systemUiVisibility = View.GONE
+ } else if (Build.VERSION.SDK_INT >= 19) {
+ //for new api versions.
+ val decorView = activity.window.decorView
+ val uiOptions = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
+ // | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
+ or View.SYSTEM_UI_FLAG_IMMERSIVE)
+ decorView.systemUiVisibility = uiOptions
+ activity.window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+
+ //获取屏幕真实高度,不包含下方虚拟导航栏
+ fun getRealHeight(context: Context): Int {
+ val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
+ val display = windowManager.defaultDisplay
+ val dm = DisplayMetrics()
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ display.getRealMetrics(dm)
+ } else {
+ display.getMetrics(dm)
+ }
+ return dm.heightPixels
+ }
+
+ //获取状态栏高度
+ fun getStatusBarHeight(context: Context): Float {
+ var height = 0f
+ val resourceId = context.applicationContext.resources.getIdentifier(
+ "status_bar_height",
+ "dimen",
+ "android"
+ )
+ if (resourceId > 0) {
+ height =
+ context.applicationContext.resources.getDimensionPixelSize(resourceId).toFloat()
+ }
+ return height
+ }
+
+ /**
+ * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
+ */
+ fun px2dip(context: Context, pxValue: Float): Float {
+ val scale = context.resources.displayMetrics.density
+ var num = if (scale <= 0) 1f else scale
+ return pxValue / num + 0.5f
+ }
+
+ /**
+ * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
+ */
+ fun dip2px(context: Context, dpValue: Float): Float {
+ val scale = context.resources.displayMetrics.density
+ return dpValue * scale + 0.5f
+ }
+
+ /**
+ * 判断是否是刘海屏
+ * @return
+ */
+ fun hasNotchScreen(activity: Activity): Boolean {
+ return if (getInt(
+ "ro.miui.notch",
+ activity
+ ) == 1 || hasNotchAtHuawei(activity) || hasNotchAtOPPO(activity)
+ || hasNotchAtVivo(activity) || isAndroidPHasNotch(activity)
+ ) {
+ true
+ } else false
+ }
+
+ /**
+ * Android P 刘海屏判断
+ * @param activity
+ * @return
+ */
+ fun isAndroidPHasNotch(activity: Activity?): Boolean {
+ var ret = false
+ if (Build.VERSION.SDK_INT >= 28) {
+ try {
+ val windowInsets = Class.forName("android.view.WindowInsets")
+ val method = windowInsets.getMethod("getDisplayCutout")
+ val displayCutout = method.invoke(windowInsets)
+ if (displayCutout != null) {
+ ret = true
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+ return ret
+ }
+
+ /**
+ * 小米刘海屏判断.
+ * @return 0 if it is not notch ; return 1 means notch
+ * @throws IllegalArgumentException if the key exceeds 32 characters
+ */
+ fun getInt(key: String?, activity: Activity): Int {
+ var result = 0
+ if (isMiui()) {
+ try {
+ val classLoader = activity.classLoader
+ val SystemProperties = classLoader.loadClass("android.os.SystemProperties")
+ //参数类型
+ val paramTypes = arrayOfNulls?>(2)
+ paramTypes[0] = String::class.java
+ paramTypes[1] = Int::class.javaPrimitiveType
+ val getInt = SystemProperties.getMethod("getInt", *paramTypes)
+ //参数
+ val params = arrayOfNulls(2)
+ params[0] = String
+ params[1] = Int
+ result = getInt.invoke(SystemProperties, *params) as Int
+ } catch (e: ClassNotFoundException) {
+ e.printStackTrace()
+ } catch (e: NoSuchMethodException) {
+ e.printStackTrace()
+ } catch (e: IllegalAccessException) {
+ e.printStackTrace()
+ } catch (e: IllegalArgumentException) {
+ e.printStackTrace()
+ } catch (e: InvocationTargetException) {
+ e.printStackTrace()
+ }
+ }
+ return result
+ }
+
+ /**
+ * 华为刘海屏判断
+ * @return
+ */
+ fun hasNotchAtHuawei(context: Context): Boolean {
+ var ret = false
+ try {
+ val classLoader = context.classLoader
+ val HwNotchSizeUtil = classLoader.loadClass("com.huawei.android.util.HwNotchSizeUtil")
+ val get = HwNotchSizeUtil.getMethod("hasNotchInScreen")
+ ret = get.invoke(HwNotchSizeUtil) as Boolean
+ } catch (e: ClassNotFoundException) {
+ } catch (e: NoSuchMethodException) {
+ } catch (e: Exception) {
+ } finally {
+ return ret
+ }
+ }
+
+ val VIVO_NOTCH = 0x00000020 //是否有刘海
+
+ val VIVO_FILLET = 0x00000008 //是否有圆角
+
+
+ /**
+ * VIVO刘海屏判断
+ * @return
+ */
+ fun hasNotchAtVivo(context: Context): Boolean {
+ var ret = false
+ try {
+ val classLoader = context.classLoader
+ val FtFeature = classLoader.loadClass("android.util.FtFeature")
+ val method = FtFeature.getMethod("isFeatureSupport", Int::class.javaPrimitiveType)
+ ret = method.invoke(FtFeature, VIVO_NOTCH) as Boolean
+ } catch (e: ClassNotFoundException) {
+ } catch (e: NoSuchMethodException) {
+ } catch (e: Exception) {
+ } finally {
+ return ret
+ }
+ }
+
+ /**
+ * OPPO刘海屏判断
+ * @return
+ */
+ fun hasNotchAtOPPO(context: Context): Boolean {
+ return context.packageManager.hasSystemFeature("com.oppo.feature.screen.heteromorphism")
+ }
+
+ fun isMiui(): Boolean {
+ var sIsMiui = false
+ try {
+ val clz = Class.forName("miui.os.Build")
+ if (clz != null) {
+ sIsMiui = true
+ return sIsMiui
+ }
+ } catch (e: Exception) {
+ // ignore
+ }
+ return sIsMiui
+ }
+}
\ No newline at end of file
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/UnionAdSsgfConfig.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/UnionAdSsgfConfig.kt
new file mode 100644
index 0000000..9cbe529
--- /dev/null
+++ b/android/src/main/kotlin/com/example/union_ad_ssgf/UnionAdSsgfConfig.kt
@@ -0,0 +1,17 @@
+package com.example.union_ad_ssgf;
+
+class UnionAdSsgfConfig {
+ companion object {
+ // event事件
+ const val adevent = "com.example.union_ad_ssgf/adevent"
+
+ // BannerAdView
+ const val bannerAdView = "com.example.union_ad_ssgf/BannerAdView"
+
+ // SplashAdView
+ const val splashAdView = "com.example.union_ad_ssgf/SplashAdView"
+
+ // NativeExpressADView
+ const val nativeAdView = "com.example.union_ad_ssgf/NativeExpressAdView"
+ }
+}
\ No newline at end of file
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/UnionAdSsgfEventPlugin.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/UnionAdSsgfEventPlugin.kt
new file mode 100644
index 0000000..a6388a9
--- /dev/null
+++ b/android/src/main/kotlin/com/example/union_ad_ssgf/UnionAdSsgfEventPlugin.kt
@@ -0,0 +1,38 @@
+package com.example.union_ad_ssgf;
+
+import android.content.Context
+import io.flutter.embedding.engine.plugins.FlutterPlugin
+import io.flutter.plugin.common.EventChannel
+
+class UnionAdSsgfEventPlugin : FlutterPlugin, EventChannel.StreamHandler {
+ companion object {
+ private var eventChannel: EventChannel? = null
+
+ private var eventSink: EventChannel.EventSink? = null
+
+ private var context: Context? = null
+
+ fun sendContent(content: MutableMap) {
+ eventSink?.success(content);
+ }
+ }
+
+ override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
+ eventSink = events
+ }
+
+ override fun onCancel(arguments: Any?) {
+ eventSink = null
+ }
+
+ override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
+ eventChannel = EventChannel(binding.binaryMessenger, UnionAdSsgfConfig.adevent)
+ eventChannel!!.setStreamHandler(this)
+ context = binding.applicationContext
+ }
+
+ override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
+ eventChannel = null
+ eventChannel!!.setStreamHandler(null)
+ }
+}
\ No newline at end of file
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/UnionAdSsgfPlugin.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/UnionAdSsgfPlugin.kt
index a40bd9a..c1bb2b9 100644
--- a/android/src/main/kotlin/com/example/union_ad_ssgf/UnionAdSsgfPlugin.kt
+++ b/android/src/main/kotlin/com/example/union_ad_ssgf/UnionAdSsgfPlugin.kt
@@ -1,87 +1,117 @@
-package com.example.union_ad_ssgf
+package com.example.union_ad_ssgf;
-
-import io.flutter.embedding.engine.plugins.FlutterPlugin;
-import io.flutter.embedding.engine.plugins.activity.ActivityAware;
-import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
-import io.flutter.plugin.common.EventChannel;
-import io.flutter.plugin.common.MethodChannel;
+import android.app.Activity
+import android.content.Context
+import android.util.Log
+import androidx.annotation.NonNull
+import com.example.union_ad_ssgf.interstitialad.InterstitialAd
+import com.example.union_ad_ssgf.rewardvideoad.RewardVideoAd
+import com.qq.e.comm.DownloadService
+import com.qq.e.comm.managers.GDTAdSdk
+import com.qq.e.comm.managers.setting.GlobalSetting
+import com.qq.e.comm.managers.status.SDKStatus
+import io.flutter.embedding.engine.plugins.FlutterPlugin
+import io.flutter.embedding.engine.plugins.activity.ActivityAware
+import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
+import io.flutter.plugin.common.MethodCall
+import io.flutter.plugin.common.MethodChannel
+import io.flutter.plugin.common.MethodChannel.MethodCallHandler
+import io.flutter.plugin.common.MethodChannel.Result
+import java.lang.Exception
/**
- * 三商共富 - 三方插件
+ * 腾讯优量汇插件
*/
-class UnionAdSsgfPlugin : FlutterPlugin, ActivityAware {
- /**
- * 方法通道:
- *
- * 用于Flutter与原生Android之间通信的 MethodChannel
- * 此本地引用用于向Flutter引擎注册插件,并在Flutter引擎与Activity分离时注销它
- */
- private lateinit var methodChannel: MethodChannel
+class UnionAdSsgfPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
- /**
- * 事件通道
- *
- * 用于Flutter与原生Android之间通信的 EventChannel
- * 此本地引用用于向Flutter引擎注册插件,并在Flutter引擎与Activity分离时注销它
- */
- private lateinit var eventChannel: EventChannel
+ private lateinit var channel: MethodChannel
+ private var applicationContext: Context? = null
+ private var mActivity: Activity? = null
+ private var mFlutterPluginBinding: FlutterPlugin.FlutterPluginBinding? = null
-
- /**
- * 插件代理
- */
- var delegate: PluginDelegate? = null
-
-
- /**
- * 插件连接器
- */
- private lateinit var bind: FlutterPlugin.FlutterPluginBinding
-
- /**
- * 初始化方法通道和事件通道
- */
- override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
- bind = flutterPluginBinding
-
- // 注册 - 方法通道
- methodChannel = MethodChannel(flutterPluginBinding.binaryMessenger, "union_ad_ssgf_method")
-
- // 注册 - 监听通道
- eventChannel = EventChannel(flutterPluginBinding.getBinaryMessenger(), "union_ad_ssgf_event")
- }
-
- /**
- * 注销通道
- */
- override fun onDetachedFromEngine(p0: FlutterPlugin.FlutterPluginBinding) {
- // 解除 - 方法通道
- methodChannel.setMethodCallHandler(null)
-
- // 解除 - 事件通道
- eventChannel.setStreamHandler(null)
- }
-
- /**
- * 绑定activity
- */
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
- delegate = PluginDelegate(binding.activity, bind)
- methodChannel.setMethodCallHandler(delegate)
- eventChannel.setStreamHandler(delegate)
- }
-
-
- override fun onDetachedFromActivityForConfigChanges() {
- onDetachedFromActivity()
+ mActivity = binding.activity
+ Log.e("UnionAdSsgfPlugin->", "onAttachedToActivity");
+ UnionAdSsgfViewPlugin.registerWith(mFlutterPluginBinding!!, mActivity!!)
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
- onAttachedToActivity(binding)
+ mActivity = binding.activity
+ Log.e("UnionAdSsgfPlugin->", "onReattachedToActivityForConfigChanges")
+ }
+
+ override fun onDetachedFromActivityForConfigChanges() {
+ mActivity = null
+ Log.e("UnionAdSsgfPlugin->", "onDetachedFromActivityForConfigChanges")
}
override fun onDetachedFromActivity() {
- this.delegate = null
+ mActivity = null
+ Log.e("UnionAdSsgfPlugin->", "onDetachedFromActivity")
+ }
+
+ override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
+ channel = MethodChannel(flutterPluginBinding.binaryMessenger, "flutter_union_ad")
+ channel.setMethodCallHandler(this)
+ applicationContext = flutterPluginBinding.applicationContext
+ mFlutterPluginBinding = flutterPluginBinding
+ UnionAdSsgfEventPlugin().onAttachedToEngine(flutterPluginBinding)
+ }
+
+ override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
+ //注册初始化
+ if (call.method == "register") {
+ val appId = call.argument("androidId")
+ val debug = call.argument("debug")
+ val channelId = call.argument("channelId")
+ val personalized = call.argument("personalized")
+ // 日志
+ LogUtil.setAppName("flutter_union_ad")
+ LogUtil.setShow(debug!!)
+ // 是否开启个性化
+ GlobalSetting.setPersonalizedState(personalized!!)
+ // 设置渠道id
+ GlobalSetting.setChannel(channelId!!)
+ GDTAdSdk.initWithoutStart(applicationContext, appId)
+ GDTAdSdk.start(object : GDTAdSdk.OnStartListener {
+ override fun onStartSuccess() {
+ result.success(true)
+ }
+
+ override fun onStartFailed(p0: Exception?) {
+ result.success(false)
+ }
+
+ })
+ // 获取sdk版本
+ } else if (call.method == "getSDKVersion") {
+ result.success(SDKStatus.getIntegrationSDKVersion())
+ // 预加载激励广告
+ } else if (call.method == "loadRewardVideoAd") {
+ RewardVideoAd.init(applicationContext!!, call.arguments as Map<*, *>)
+ result.success(true)
+ // 展示激励广告
+ } else if (call.method == "showRewardVideoAd") {
+ RewardVideoAd.showAd(call.arguments as Map<*, *>)
+ result.success(true)
+ // 预加载插屏广告
+ } else if (call.method == "loadInterstitialAD") {
+ InterstitialAd.init(mActivity!!, call.arguments as Map<*, *>)
+ result.success(true)
+ // 展示插屏广告
+ } else if (call.method == "showInterstitialAD") {
+ InterstitialAd.showAd(call.arguments as Map<*, *>)
+ result.success(true)
+ // 进入下载列表
+ } else if (call.method == "enterAPPDownloadListPage") {
+ DownloadService.enterAPPDownloadListPage(mActivity)
+ result.success(true)
+ } else {
+ result.notImplemented()
+ }
+ }
+
+ override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
+ channel.setMethodCallHandler(null)
}
}
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/UnionAdSsgfViewPlugin.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/UnionAdSsgfViewPlugin.kt
new file mode 100644
index 0000000..ec096f0
--- /dev/null
+++ b/android/src/main/kotlin/com/example/union_ad_ssgf/UnionAdSsgfViewPlugin.kt
@@ -0,0 +1,27 @@
+package com.example.union_ad_ssgf;
+
+import android.app.Activity
+import com.example.union_ad_ssgf.bannerad.BannerAdViewFactory
+import com.example.union_ad_ssgf.expressad.NativeExpressAdViewFactory
+import com.example.union_ad_ssgf.splashad.SplashAdViewFactory
+import io.flutter.embedding.engine.plugins.FlutterPlugin
+
+object UnionAdSsgfViewPlugin {
+ fun registerWith(binding: FlutterPlugin.FlutterPluginBinding, activity: Activity) {
+ // 注册banner广告
+ binding.platformViewRegistry.registerViewFactory(
+ UnionAdSsgfConfig.bannerAdView,
+ BannerAdViewFactory(binding.binaryMessenger, activity)
+ )
+ // 注册splash广告
+ binding.platformViewRegistry.registerViewFactory(
+ UnionAdSsgfConfig.splashAdView,
+ SplashAdViewFactory(binding.binaryMessenger, activity)
+ )
+ // 注册Express广告
+ binding.platformViewRegistry.registerViewFactory(
+ UnionAdSsgfConfig.nativeAdView,
+ NativeExpressAdViewFactory(binding.binaryMessenger, activity)
+ )
+ }
+}
\ No newline at end of file
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/bannerad/BannerAdView.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/bannerad/BannerAdView.kt
new file mode 100644
index 0000000..73a8985
--- /dev/null
+++ b/android/src/main/kotlin/com/example/union_ad_ssgf/bannerad/BannerAdView.kt
@@ -0,0 +1,175 @@
+package com.example.union_ad_ssgf.bannerad
+
+import android.app.Activity
+import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import com.example.union_ad_ssgf.*
+import com.qq.e.ads.banner2.UnifiedBannerADListener
+import com.qq.e.ads.banner2.UnifiedBannerView
+import com.qq.e.comm.pi.IBidding
+import com.qq.e.comm.util.AdError
+import io.flutter.plugin.common.BinaryMessenger
+import io.flutter.plugin.common.MethodCall
+import io.flutter.plugin.common.MethodChannel
+import io.flutter.plugin.platform.PlatformView
+
+/**
+ * @Description: 平台模板Banner广告
+ **/
+
+internal class BannerAdView(
+ var activity: Activity,
+ messenger: BinaryMessenger,
+ id: Int,
+ params: Map
+) :
+ PlatformView, UnifiedBannerADListener, MethodChannel.MethodCallHandler {
+
+ private val TAG = "BannerAdView"
+
+ private var mContainer: FrameLayout? = null
+
+ //广告所需参数
+ private var codeId: String
+ private var viewWidth: Float
+ private var viewHeight: Float
+
+ private var unifiedBannerView: UnifiedBannerView? = null
+
+ private var channel: MethodChannel?
+
+ private var downloadConfirm: Boolean
+ //是否开启竞价
+ private var isBidding: Boolean = params["isBidding"] as Boolean
+
+
+ init {
+ codeId = params["androidId"] as String
+ var width = params["viewWidth"] as Double
+ var height = params["viewHeight"] as Double
+ downloadConfirm = params["downloadConfirm"] as Boolean
+ viewWidth = width.toFloat()
+ viewHeight = height.toFloat()
+ mContainer = FrameLayout(activity)
+ mContainer?.layoutParams?.width = ViewGroup.LayoutParams.WRAP_CONTENT
+ mContainer?.layoutParams?.height = ViewGroup.LayoutParams.WRAP_CONTENT
+ channel = MethodChannel(messenger, UnionAdSsgfConfig.bannerAdView + "_" + id)
+ channel?.setMethodCallHandler(this)
+ loadBannerAd()
+ }
+
+ private fun loadBannerAd() {
+ unifiedBannerView = UnifiedBannerView(activity, codeId, this)
+ unifiedBannerView?.loadAD()
+ }
+
+ override fun getView(): View {
+ return mContainer!!
+ }
+
+
+ //广告加载失败,error 对象包含了错误码和错误信息
+ override fun onNoAD(p0: AdError?) {
+ LogUtil.e("$TAG Banner广告加载失败 ${p0?.errorCode} ${p0?.errorMsg}")
+ var map: MutableMap =
+ mutableMapOf("code" to p0?.errorCode, "message" to p0?.errorMsg)
+ channel?.invokeMethod("onFail", map)
+ }
+
+ //广告加载成功回调,表示广告相关的资源已经加载完毕,Ready To Show
+ override fun onADReceive() {
+ mContainer?.removeAllViews()
+ if (unifiedBannerView == null) {
+ LogUtil.e("$TAG Banner广告加载失败 unifiedBannerView不存在或已销毁")
+ var map: MutableMap =
+ mutableMapOf("code" to 0, "message" to "BannerView不存在或已销毁")
+ channel?.invokeMethod("onFail", map)
+ return
+ }
+ if (downloadConfirm) {
+ unifiedBannerView?.setDownloadConfirmListener(DownloadConfirmHelper.DOWNLOAD_CONFIRM_LISTENER)
+ }
+ //竞价 则返回价格 不直接加载
+ if (isBidding) {
+ channel?.invokeMethod("onECPM", mutableMapOf(
+ "ecpmLevel" to unifiedBannerView?.ecpmLevel,
+ "ecpm" to unifiedBannerView?.ecpm
+ ))
+ } else {
+ LogUtil.e("$TAG Banner广告加载成功回调")
+ mContainer?.addView(unifiedBannerView)
+ val map: MutableMap = mutableMapOf(
+ "width" to UIUtils.px2dip(activity, unifiedBannerView?.width!!.toFloat()),
+ "height" to UIUtils.px2dip(activity, unifiedBannerView?.height!!.toFloat())
+ )
+ channel?.invokeMethod("onShow", map)
+ }
+ }
+
+ //当广告曝光时发起的回调
+ override fun onADExposure() {
+ LogUtil.e("$TAG Banner广告曝光")
+ channel?.invokeMethod("onExpose", "")
+ }
+
+ //当广告关闭时调用
+ override fun onADClosed() {
+ LogUtil.e("$TAG Banner广告关闭")
+ channel?.invokeMethod("onClose", "")
+ }
+
+ //当广告点击时发起的回调,由于点击去重等原因可能和平台最终的统计数据有差异
+ override fun onADClicked() {
+ LogUtil.e("$TAG Banner广告点击")
+ channel?.invokeMethod("onClick", "")
+ }
+
+ //由于广告点击离开 APP 时调用
+ override fun onADLeftApplication() {
+ LogUtil.e("$TAG Banner广告点击离开 APP")
+ }
+
+ override fun dispose() {
+ unifiedBannerView?.destroy()
+ unifiedBannerView = null
+ }
+
+ override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
+ when (call.method) {
+ //竞价成功
+ "biddingSucceeded" -> {
+ var arguments = call.arguments as Map<*, *>
+ val map: MutableMap = mutableMapOf(
+ //对应值为竞胜出价,类型为Integer
+ IBidding.EXPECT_COST_PRICE to arguments["expectCostPrice"],
+ //对应值为最大竞败方出价,类型为Integer
+ IBidding.HIGHEST_LOSS_PRICE to arguments["highestLossPrice"],
+ )
+ unifiedBannerView?.sendWinNotification(map)
+ //展示banner
+ mContainer?.addView(unifiedBannerView)
+ val map2: MutableMap = mutableMapOf(
+ "width" to UIUtils.px2dip(activity, unifiedBannerView?.width!!.toFloat()),
+ "height" to UIUtils.px2dip(activity, unifiedBannerView?.height!!.toFloat())
+ )
+ channel?.invokeMethod("onShow", map2)
+ }
+ //竞价失败
+ "biddingFail" -> {
+ var arguments = call.arguments as Map<*, *>
+ val map: MutableMap = mutableMapOf(
+ //值为本次竞胜方出价(单位:分),类型为Integer。选填
+ IBidding.WIN_PRICE to arguments["winPrice"],
+ //值为优量汇广告竞败原因,类型为Integer。必填
+ IBidding.LOSS_REASON to arguments["lossReason"],
+ //值为本次竞胜方渠道ID,类型为Integer。必填。
+ IBidding.ADN_ID to arguments["adnId"],
+ )
+ unifiedBannerView?.sendLossNotification(map)
+ }
+
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/bannerad/BannerAdViewFactory.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/bannerad/BannerAdViewFactory.kt
new file mode 100644
index 0000000..a872302
--- /dev/null
+++ b/android/src/main/kotlin/com/example/union_ad_ssgf/bannerad/BannerAdViewFactory.kt
@@ -0,0 +1,17 @@
+package com.example.union_ad_ssgf.bannerad
+
+import android.app.Activity
+import android.content.Context
+import io.flutter.plugin.common.BinaryMessenger
+import io.flutter.plugin.common.StandardMessageCodec
+import io.flutter.plugin.platform.PlatformView
+import io.flutter.plugin.platform.PlatformViewFactory
+
+internal class BannerAdViewFactory(private val messenger: BinaryMessenger, private val activity: Activity) : PlatformViewFactory(
+ StandardMessageCodec.INSTANCE) {
+
+ override fun create(context: Context?, viewId: Int, args: Any?): PlatformView {
+ val params = args as Map
+ return BannerAdView(activity,messenger, viewId, params)
+ }
+}
\ No newline at end of file
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/config/UnionADConfig.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/config/UnionADConfig.kt
deleted file mode 100644
index 69cd85d..0000000
--- a/android/src/main/kotlin/com/example/union_ad_ssgf/config/UnionADConfig.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.example.union_ad_ssgf.config
-
-import android.annotation.SuppressLint
-
-class UnionADConfig {
-
- /*初始化代码块*/
- init {
- _instance = this
- }
-
- companion object {
- // 插件代理对象
- @SuppressLint("StaticFieldLeak")
- private lateinit var _instance: UnionADConfig
-
- fun getInstance(): UnionADConfig {
- return _instance
- }
-
- // Banner View
- const val KEY_BANNER_VIEW = "flutter_qq_ads_banner"
-
- // Feed View
- const val KEY_FEED_VIEW = "flutter_qq_ads_feed"
-
- // 广告参数
- const val KEY_POSID = "posId"
-
- // 广告参数
- const val KEY_ADID = "adId"
-
- // logo 参数
- const val KEY_LOGO = "logo"
-
- // fetchDelay 参数
- const val KEY_FETCH_DELAY = "fetchDelay"
- }
-
-}
\ No newline at end of file
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdErrorEvent.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdErrorEvent.kt
deleted file mode 100644
index ccacf37..0000000
--- a/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdErrorEvent.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.example.union_ad_ssgf.event
-
-
-class AdErrorEvent(posId: String?, adId: String?, viewId: Int?, errCode: Int, errMsg: String?) :
- AdEvent(posId, adId, viewId, AdEventAction.onAdError) {
- // 错误码
- private var errCode = 0
-
- // 错误信息
- private var errMsg: String? = null
-
- // 错误事件实体
- init {
- this.errMsg = errMsg
- this.errCode = errCode
- }
-
- /**
- * 重写 toMap 方法
- * @return 返回错误事件的map
- */
- override fun toMap(): HashMap {
- val newMap = super.toMap()
- newMap["errCode"] = errCode
- newMap["errMsg"] = errMsg
- return newMap
- }
-}
\ No newline at end of file
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdEvent.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdEvent.kt
deleted file mode 100644
index 4382717..0000000
--- a/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdEvent.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.example.union_ad_ssgf.event
-
-import java.util.HashMap
-
-open class AdEvent(posId: String?, adId: String?, viewId: Int?, action: String?) {
- // 广告位 id
- private var posId: String? = null
-
- // 广告 id
- private var adId: String? = null
-
- private var viewId: Int? = null
-
- // 操作
- private var action: String? = null
-
- init {
- this.adId = adId
- this.posId = posId
- this.action = action
- this.viewId = viewId
- }
-
- /**
- * 转换为 Map 方面传输
- * @return 转换后的 Map 对象
- */
- open fun toMap(): HashMap {
- val map = HashMap()
- map["adId"] = adId
- map["posId"] = posId
- map["action"] = action
- map["viewId"] = viewId
- return map
- }
-}
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdEventAction.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdEventAction.kt
deleted file mode 100644
index 1f92f89..0000000
--- a/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdEventAction.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.example.union_ad_ssgf.event
-
-class AdEventAction {
- companion object {
- // 广告错误
- val onAdError = "onAdError"
-
- // 广告加载成功
- val onAdLoaded = "onAdLoaded"
-
- // 广告填充
- val onAdPresent = "onAdPresent"
-
- // 广告曝光
- val onAdExposure = "onAdExposure"
-
- // 广告关闭
- val onAdClosed = "onAdClosed"
-
- // 广告点击
- val onAdClicked = "onAdClicked"
-
- // 广告跳过
- val onAdSkip = "onAdSkip"
-
- // 广告播放或计时完毕
- val onAdComplete = "onAdComplete"
-
- // 获得广告激励
- val onAdReward = "onAdReward"
- }
-}
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdEventHandler.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdEventHandler.kt
deleted file mode 100644
index 21dccc8..0000000
--- a/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdEventHandler.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.example.union_ad_ssgf.event
-
-
-class AdEventHandler {
- companion object {
-
- // 广告事件处理对象
- @Volatile private var _instance: AdEventHandler? = null
-
- /**
- * 获取广告事件处理类
- * @return 广告事件处理对象
- */
- fun getInstance(): AdEventHandler? {
- if (_instance == null) {
- synchronized(AdEventHandler::class.java) { _instance = AdEventHandler() }
- }
- return _instance
- }
- }
-
- /**
- * 添加广告事件
- * @param event 广告事件
- */
- fun sendEvent(event: AdEvent?) {
- if (event != null) {
-// PluginDelegate.getInstance().addEvent(event.toMap())
- }
- }
-}
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdRewardEvent.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdRewardEvent.kt
deleted file mode 100644
index 62f1515..0000000
--- a/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdRewardEvent.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.example.union_ad_ssgf.event
-
-
-/**
- * @param transId 服务端验证唯一id
- * @param customData 服务端验证的自定义信息
- * @param userId 服务端验证的用户信息
- */
-class AdRewardEvent(
- posId: String?,
- adId: String?,
- viewId: Int?,
- action: String?,
- var transId: String,
- var customData: String,
- var userId: String,
-) : AdEvent(posId, adId, viewId, action) {
- override fun toMap(): HashMap {
- val newMap = super.toMap()
- newMap["transId"] = transId
- newMap["customData"] = customData
- newMap["userId"] = userId
- return newMap
- }
-}
\ No newline at end of file
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/expressad/NativeExpressAdView.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/expressad/NativeExpressAdView.kt
new file mode 100644
index 0000000..a126a57
--- /dev/null
+++ b/android/src/main/kotlin/com/example/union_ad_ssgf/expressad/NativeExpressAdView.kt
@@ -0,0 +1,267 @@
+package com.example.union_ad_ssgf.expressad
+
+import android.app.Activity
+import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import com.example.union_ad_ssgf.*
+import com.qq.e.ads.cfg.VideoOption
+import com.qq.e.ads.nativ.ADSize
+import com.qq.e.ads.nativ.NativeExpressAD
+import com.qq.e.ads.nativ.NativeExpressADView
+import com.qq.e.ads.nativ.NativeExpressMediaListener
+import com.qq.e.comm.constants.AdPatternType
+import com.qq.e.comm.pi.IBidding
+import com.qq.e.comm.util.AdError
+import io.flutter.plugin.common.BinaryMessenger
+import io.flutter.plugin.common.MethodCall
+import io.flutter.plugin.common.MethodChannel
+import io.flutter.plugin.platform.PlatformView
+
+/**
+ * @Description: 平台模板NativeExpressAdView广告
+ **/
+internal class NativeExpressAdView(
+ var activity: Activity,
+ messenger: BinaryMessenger,
+ id: Int,
+ params: Map
+) :
+ PlatformView, NativeExpressAD.NativeExpressADListener, NativeExpressMediaListener ,
+ MethodChannel.MethodCallHandler {
+
+ private var mContainer: FrameLayout? = null
+
+ //广告所需参数
+ private var codeId: String = params["androidId"] as String
+ private var viewWidth: Int = params["viewWidth"] as Int
+ private var viewHeight: Int = params["viewHeight"] as Int
+ private var downloadConfirm: Boolean = params["downloadConfirm"] as Boolean
+
+ //是否开启竞价
+ private var isBidding: Boolean = params["isBidding"] as Boolean
+
+ private var nativeExpressAD: NativeExpressAD? = null
+ private var nativeExpressAdView: NativeExpressADView? = null
+
+ private var channel: MethodChannel?
+
+
+ init {
+ mContainer = FrameLayout(activity)
+ mContainer?.layoutParams?.width = ViewGroup.LayoutParams.WRAP_CONTENT
+ mContainer?.layoutParams?.height = ViewGroup.LayoutParams.WRAP_CONTENT
+ channel = MethodChannel(messenger, UnionAdSsgfConfig.nativeAdView + "_" + id)
+ channel?.setMethodCallHandler(this)
+ loadExpressAd()
+ }
+
+ private fun loadExpressAd() {
+ val adSize: ADSize = when {
+ viewWidth == 0 -> {
+ ADSize(ADSize.FULL_WIDTH, viewHeight)
+ }
+ viewHeight == 0 -> {
+ ADSize(viewWidth, ADSize.AUTO_HEIGHT)
+ }
+ else -> {
+ ADSize(viewWidth, viewHeight)
+ }
+ }
+ nativeExpressAD = NativeExpressAD(activity, adSize, codeId, this)
+ nativeExpressAD?.setVideoOption(
+ VideoOption.Builder()
+ .setAutoPlayPolicy(VideoOption.AutoPlayPolicy.ALWAYS)
+ .setAutoPlayMuted(true)
+ .build()
+ )
+ nativeExpressAD?.loadAD(1)
+ }
+
+ override fun getView(): View {
+ return mContainer!!
+ }
+
+ /**************平台模板广告加载、渲染、点击状态的回调。****************/
+
+ //无广告填充
+ override fun onNoAD(p0: AdError?) {
+ LogUtil.e("广告加载失败 ${p0?.errorCode} ${p0?.errorMsg}")
+ val map: MutableMap =
+ mutableMapOf("code" to p0?.errorCode, "message" to p0?.errorMsg)
+ channel?.invokeMethod("onFail", map)
+ }
+
+ //广告数据加载成功,返回了可以用来展示广告的 NativeExpressADView,
+ // 但是想让广告曝光还需要调用 NativeExpressADView 的 render 方法
+ override fun onADLoaded(p0: MutableList?) {
+ // 释放前一个 NativeExpressADView 的资源
+ if (nativeExpressAdView != null) {
+ nativeExpressAdView?.destroy()
+ nativeExpressAdView = null
+ }
+ if (p0?.size == 0) {
+ LogUtil.e("未拉取到广告")
+ val map: MutableMap = mutableMapOf("code" to 0, "message" to "未拉取到广告")
+ channel?.invokeMethod("onFail", map)
+ }
+ LogUtil.e("广告数据加载成功")
+ nativeExpressAdView = p0!![0]
+ if (nativeExpressAdView?.boundData?.adPatternType == AdPatternType.NATIVE_VIDEO) {
+ nativeExpressAdView?.setMediaListener(this)
+ }
+ if (downloadConfirm) {
+ nativeExpressAdView?.setDownloadConfirmListener(DownloadConfirmHelper.DOWNLOAD_CONFIRM_LISTENER)
+ }
+ //竞价 则返回价格 不直接加载
+ if (isBidding) {
+ channel?.invokeMethod("onECPM", mutableMapOf(
+ "ecpmLevel" to nativeExpressAdView?.ecpmLevel,
+ "ecpm" to nativeExpressAdView?.ecpm
+ ))
+ } else {
+ if (nativeExpressAdView != null) {
+ if (mContainer?.childCount!! > 0) {
+ mContainer?.removeAllViews()
+ }
+ mContainer?.addView(nativeExpressAdView!!.rootView)
+ nativeExpressAdView!!.render()
+ }
+ }
+ }
+
+ //NativeExpressADView 渲染广告失败
+ override fun onRenderFail(p0: NativeExpressADView?) {
+ LogUtil.e("渲染广告失败")
+ val map: MutableMap = mutableMapOf("code" to 0, "message" to "渲染广告失败")
+ channel?.invokeMethod("onFail", map)
+ nativeExpressAdView?.destroy()
+ }
+
+ //NativeExpressADView 渲染广告成功
+ override fun onRenderSuccess(p0: NativeExpressADView?) {
+ val map: MutableMap = mutableMapOf(
+ "width" to UIUtils.px2dip(activity, p0?.width!!.toFloat()),
+ "height" to UIUtils.px2dip(activity, p0?.height!!.toFloat())
+ )
+ channel?.invokeMethod("onShow", map)
+ }
+
+ //广告曝光
+ override fun onADExposure(p0: NativeExpressADView?) {
+ LogUtil.e("广告曝光")
+ channel?.invokeMethod("onExpose", "")
+ }
+
+ //广告点击
+ override fun onADClicked(p0: NativeExpressADView?) {
+ LogUtil.e("广告点击")
+ channel?.invokeMethod("onClick", "")
+ }
+
+ //广告被关闭,将不再显示广告,此时广告对象已经释放资源,不可以再次用来展示了
+ override fun onADClosed(p0: NativeExpressADView?) {
+ LogUtil.e("广告被关闭")
+ channel?.invokeMethod("onClose", "")
+ p0?.destroy()
+ }
+
+ //因为广告点击等原因离开当前 app 时调用
+ override fun onADLeftApplication(p0: NativeExpressADView?) {
+ LogUtil.e("因为广告点击等原因离开当前 app")
+ }
+
+ /*****************平台模板视频广告播放状态回调接口,专用于带有视频素材的广告对象**************/
+
+ //视频播放 View 初始化完成
+ override fun onVideoInit(p0: NativeExpressADView?) {
+ LogUtil.e("视频播放 View 初始化完成")
+ }
+
+ //视频下载中
+ override fun onVideoLoading(p0: NativeExpressADView?) {
+ LogUtil.e("视频下载中")
+ }
+
+ //视频下载完成
+ override fun onVideoCached(p0: NativeExpressADView?) {
+ LogUtil.e("视频下载完成")
+// nativeExpressAdView?.
+ }
+
+ //视频播放器初始化完成,准备好可以播放了,videoDuration 是视频素材的时间长度,单位为 ms
+ override fun onVideoReady(p0: NativeExpressADView?, p1: Long) {
+ LogUtil.e("视频播放器初始化完成")
+// nativeExpressAdView?
+ }
+
+ //视频开始播放
+ override fun onVideoStart(p0: NativeExpressADView?) {
+ LogUtil.e("视频开始播放")
+ }
+
+ //视频暂停
+ override fun onVideoPause(p0: NativeExpressADView?) {
+ LogUtil.e("视频暂停")
+ }
+
+ //视频播放结束,手动调用 stop 或者自然播放到达最后一帧时都会触发
+ override fun onVideoComplete(p0: NativeExpressADView?) {
+ LogUtil.e("视频播放结束")
+ }
+
+ //视频播放时出现错误,error 对象包含了错误码和错误信息,错误码的详细内容可以参考文档第5章
+ override fun onVideoError(p0: NativeExpressADView?, p1: AdError?) {
+ LogUtil.e("视频播放时出现错误 ${p1?.errorCode} ${p1?.errorMsg}")
+ }
+
+ //进入视频落地页
+ override fun onVideoPageOpen(p0: NativeExpressADView?) {
+ LogUtil.e("进入视频落地页")
+ }
+
+ //退出视频落地页
+ override fun onVideoPageClose(p0: NativeExpressADView?) {
+ LogUtil.e("退出视频落地页")
+
+ }
+
+ override fun dispose() {
+ nativeExpressAdView?.destroy()
+ mContainer?.removeAllViews()
+ }
+
+ override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
+ when (call.method){
+ //竞价成功
+ "biddingSucceeded" -> {
+ var arguments = call.arguments as Map<*, *>
+ val map: MutableMap = mutableMapOf(
+ //对应值为竞胜出价,类型为Integer
+ IBidding.EXPECT_COST_PRICE to arguments["expectCostPrice"],
+ //对应值为最大竞败方出价,类型为Integer
+ IBidding.HIGHEST_LOSS_PRICE to arguments["highestLossPrice"],
+ )
+ nativeExpressAdView?.sendWinNotification(map)
+ //展示信息流
+ mContainer?.addView(nativeExpressAdView!!.rootView)
+ nativeExpressAdView!!.render()
+ }
+ //竞价失败
+ "biddingFail" -> {
+ var arguments = call.arguments as Map<*, *>
+ val map: MutableMap = mutableMapOf(
+ //值为本次竞胜方出价(单位:分),类型为Integer。选填
+ IBidding.WIN_PRICE to arguments["winPrice"],
+ //值为优量汇广告竞败原因,类型为Integer。必填
+ IBidding.LOSS_REASON to arguments["lossReason"],
+ //值为本次竞胜方渠道ID,类型为Integer。必填。
+ IBidding.ADN_ID to arguments["adnId"],
+ )
+ nativeExpressAdView?.sendLossNotification(map)
+ }
+
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/expressad/NativeExpressAdViewFactory.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/expressad/NativeExpressAdViewFactory.kt
new file mode 100644
index 0000000..c0f5290
--- /dev/null
+++ b/android/src/main/kotlin/com/example/union_ad_ssgf/expressad/NativeExpressAdViewFactory.kt
@@ -0,0 +1,17 @@
+package com.example.union_ad_ssgf.expressad
+
+import android.app.Activity
+import android.content.Context
+import io.flutter.plugin.common.BinaryMessenger
+import io.flutter.plugin.common.StandardMessageCodec
+import io.flutter.plugin.platform.PlatformView
+import io.flutter.plugin.platform.PlatformViewFactory
+
+internal class NativeExpressAdViewFactory(private val messenger: BinaryMessenger, private val activity: Activity) : PlatformViewFactory(
+ StandardMessageCodec.INSTANCE) {
+
+ override fun create(context: Context?, viewId: Int, args: Any?): PlatformView {
+ val params = args as Map
+ return NativeExpressAdView(activity,messenger, viewId, params)
+ }
+}
\ No newline at end of file
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/interstitialad/InterstitialAd.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/interstitialad/InterstitialAd.kt
new file mode 100644
index 0000000..b344d5f
--- /dev/null
+++ b/android/src/main/kotlin/com/example/union_ad_ssgf/interstitialad/InterstitialAd.kt
@@ -0,0 +1,227 @@
+package com.example.union_ad_ssgf.interstitialad
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import com.example.union_ad_ssgf.DownloadConfirmHelper
+import com.example.union_ad_ssgf.LogUtil
+import com.qq.e.ads.interstitial2.UnifiedInterstitialAD
+import com.qq.e.ads.interstitial2.UnifiedInterstitialADListener
+import com.example.union_ad_ssgf.UnionAdSsgfEventPlugin
+import com.qq.e.ads.interstitial2.ADRewardListener
+import com.qq.e.comm.pi.IBidding
+import com.qq.e.comm.util.AdError
+
+@SuppressLint("StaticFieldLeak")
+object InterstitialAd {
+ private val TAG = "InterstitialAd"
+
+ private lateinit var context: Activity
+ private var unifiedInterstitialAD: UnifiedInterstitialAD? = null
+
+ private var codeId: String? = null
+ private var isFullScreen: Boolean? = false
+ private var downloadConfirm: Boolean = false
+
+ //是否开启竞价
+ private var isBidding: Boolean = false
+
+ fun init(context: Activity, params: Map<*, *>) {
+ this.context = context
+ this.codeId = params["androidId"] as String
+ this.isFullScreen = params["isFullScreen"] as Boolean
+ this.downloadConfirm = params["downloadConfirm"] as Boolean
+ this.isBidding = params["isBidding"] as Boolean
+ loadInterstitialAD()
+ }
+
+ private fun loadInterstitialAD() {
+ unifiedInterstitialAD = UnifiedInterstitialAD(
+ context,
+ codeId,
+ interstitialADListener
+ )
+ if (isFullScreen!!) {
+ unifiedInterstitialAD?.setRewardListener(adRewardListener)
+ unifiedInterstitialAD?.loadFullScreenAD()
+ } else {
+ unifiedInterstitialAD?.loadAD()
+ }
+ }
+
+ fun showAd(params: Map<*, *>) {
+ if (unifiedInterstitialAD == null) {
+ val map: MutableMap =
+ mutableMapOf("adType" to "interactAd", "onAdMethod" to "onUnReady")
+ UnionAdSsgfEventPlugin.sendContent(map)
+ LogUtil.e("$TAG 插屏全屏视频广告显示失败,无广告")
+ return
+ }
+ // 广告是否有效,无效广告将无法展示
+ if (!unifiedInterstitialAD?.isValid!!) {
+ val map: MutableMap = mutableMapOf(
+ "adType" to "interactAd",
+ "onAdMethod" to "onFail",
+ "code" to 1,
+ "message" to "插屏全屏视频视频广告显示失败,无效广告"
+ )
+ UnionAdSsgfEventPlugin.sendContent(map)
+ LogUtil.e("$TAG 插屏全屏视频广告显示失败,无效广告")
+ unifiedInterstitialAD?.close()
+ unifiedInterstitialAD?.destroy()
+ unifiedInterstitialAD = null
+ return
+ }
+ //是否为竞价模式
+ if (isBidding) {
+ val isSuccess: Boolean = params["isSuccess"] as Boolean
+ //是否成功
+ if (isSuccess) {
+ unifiedInterstitialAD?.sendWinNotification(
+ mutableMapOf(
+ //对应值为竞胜出价,类型为Integer
+ IBidding.EXPECT_COST_PRICE to params["expectCostPrice"],
+ //对应值为最大竞败方出价,类型为Integer
+ IBidding.HIGHEST_LOSS_PRICE to params["highestLossPrice"],
+ )
+ )
+ if (isFullScreen!!) {
+ unifiedInterstitialAD?.showFullScreenAD(context)
+ } else {
+ unifiedInterstitialAD?.show()
+ }
+ } else {
+ unifiedInterstitialAD?.sendLossNotification(
+ mutableMapOf(
+ //值为本次竞胜方出价(单位:分),类型为Integer。选填
+ IBidding.WIN_PRICE to params["winPrice"],
+ //值为优量汇广告竞败原因,类型为Integer。必填
+ IBidding.LOSS_REASON to params["lossReason"],
+ //值为本次竞胜方渠道ID,类型为Integer。必填。
+ IBidding.ADN_ID to params["adnId"],
+ )
+ )
+ }
+ } else {
+ if (isFullScreen!!) {
+ unifiedInterstitialAD?.showFullScreenAD(context)
+ } else {
+ unifiedInterstitialAD?.show()
+ }
+ }
+ }
+
+ private var interstitialADListener = object : UnifiedInterstitialADListener {
+ //插屏全屏视频广告加载完毕,此回调后才可以调用 show 方法
+ override fun onADReceive() {
+ LogUtil.e("$TAG 插屏全屏视频广告加载完毕 $downloadConfirm")
+ if (downloadConfirm) {
+ unifiedInterstitialAD?.setDownloadConfirmListener(DownloadConfirmHelper.DOWNLOAD_CONFIRM_LISTENER)
+ }
+ }
+
+ //插屏全屏视频视频广告,视频素材下载完成
+ override fun onVideoCached() {
+ LogUtil.e("$TAG 插屏全屏视频视频广告,视频素材下载完成")
+ }
+
+ //广告加载失败,error 对象包含了错误码和错误信息
+ override fun onNoAD(p0: AdError?) {
+ LogUtil.e("$TAG 插屏全屏视频视频广告,加载失败 ${p0?.errorCode} ${p0?.errorMsg}")
+ val map: MutableMap = mutableMapOf(
+ "adType" to "interactAd",
+ "onAdMethod" to "onFail",
+ "code" to p0?.errorCode,
+ "message" to p0?.errorMsg
+ )
+ UnionAdSsgfEventPlugin.sendContent(map)
+ }
+
+ //插屏全屏视频广告展开时回调
+ override fun onADOpened() {
+ LogUtil.e("$TAG 插屏全屏视频广告展开时回调")
+ val map: MutableMap =
+ mutableMapOf("adType" to "interactAd", "onAdMethod" to "onShow")
+ UnionAdSsgfEventPlugin.sendContent(map)
+ }
+
+ //插屏全屏视频广告曝光时回调
+ override fun onADExposure() {
+ LogUtil.e("$TAG 插屏全屏视频广告曝光时回调")
+ val map: MutableMap =
+ mutableMapOf("adType" to "interactAd", "onAdMethod" to "onExpose")
+ UnionAdSsgfEventPlugin.sendContent(map)
+ }
+
+ //插屏全屏视频广告点击时回调
+ override fun onADClicked() {
+ LogUtil.e("$TAG 插屏全屏视频广告点击时回调")
+ val map: MutableMap =
+ mutableMapOf("adType" to "interactAd", "onAdMethod" to "onClick")
+ UnionAdSsgfEventPlugin.sendContent(map)
+ }
+
+ override fun onADLeftApplication() {
+ LogUtil.e("$TAG 插屏全屏视频视频广告,渲染成功")
+ }
+
+ //插屏全屏视频广告关闭时回调
+ override fun onADClosed() {
+ LogUtil.e("$TAG 插屏全屏视频广告关闭时回调")
+ val map: MutableMap =
+ mutableMapOf("adType" to "interactAd", "onAdMethod" to "onClose")
+ UnionAdSsgfEventPlugin.sendContent(map)
+ unifiedInterstitialAD?.close()
+ unifiedInterstitialAD?.destroy()
+ unifiedInterstitialAD = null
+ }
+
+ // 插屏全屏视频视频广告,渲染成功
+ override fun onRenderSuccess() {
+ LogUtil.e("$TAG 插屏全屏视频视频广告,渲染成功")
+ if (isBidding) {
+ val map: MutableMap =
+ mutableMapOf(
+ "adType" to "interactAd",
+ "onAdMethod" to "onECPM",
+ "ecpmLevel" to unifiedInterstitialAD?.ecpmLevel,
+ "ecpm" to unifiedInterstitialAD?.ecpm
+ )
+ UnionAdSsgfEventPlugin.sendContent(map)
+ } else {
+ val map: MutableMap =
+ mutableMapOf("adType" to "interactAd", "onAdMethod" to "onReady")
+ UnionAdSsgfEventPlugin.sendContent(map)
+ }
+ }
+
+ //插屏全屏视频视频广告,渲染失败
+ override fun onRenderFail() {
+ LogUtil.e("$TAG 插屏全屏视频视频广告,渲染失败")
+ val map: MutableMap = mutableMapOf(
+ "adType" to "interactAd",
+ "onAdMethod" to "onFail",
+ "code" to 0,
+ "message" to "插屏全屏视频视频广告渲染失败"
+ )
+ UnionAdSsgfEventPlugin.sendContent(map)
+ unifiedInterstitialAD?.close()
+ unifiedInterstitialAD?.destroy()
+ unifiedInterstitialAD = null
+ }
+
+ }
+
+
+ private var adRewardListener = object : ADRewardListener {
+ override fun onReward(p0: MutableMap?) {
+ LogUtil.e("$TAG 激励奖励 $p0")
+ val map: MutableMap = mutableMapOf(
+ "adType" to "interactAd",
+ "onAdMethod" to "onVerify",
+ "transId" to p0!!["transId"]
+ )
+ UnionAdSsgfEventPlugin.sendContent(map)
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/load/FeedAdLoad.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/load/FeedAdLoad.kt
deleted file mode 100644
index 80e271d..0000000
--- a/android/src/main/kotlin/com/example/union_ad_ssgf/load/FeedAdLoad.kt
+++ /dev/null
@@ -1,109 +0,0 @@
-package com.example.union_ad_ssgf.load
-
-import android.app.Activity
-import android.content.Intent
-import android.util.Log
-import androidx.localbroadcastmanager.content.LocalBroadcastManager
-import com.example.union_ad_ssgf.config.UnionADConfig
-import com.example.union_ad_ssgf.event.AdEventAction
-import com.example.union_ad_ssgf.page.BaseAdPage
-import com.qq.e.ads.nativ.ADSize
-import com.qq.e.ads.nativ.NativeExpressAD
-import com.qq.e.ads.nativ.NativeExpressADView
-import com.qq.e.comm.util.AdError
-import io.flutter.plugin.common.MethodCall
-import io.flutter.plugin.common.MethodChannel
-import java.util.Locale
-
-/** 信息流加载对象 */
-class FeedAdLoad : BaseAdPage(), NativeExpressAD.NativeExpressADListener {
- private val TAG = FeedAdLoad::class.java.getSimpleName()
- private var result: MethodChannel.Result? = null
-
- /**
- * 加载信息流广告列表
- * @param call
- * @param result
- */
- fun loadFeedAdList(activity: Activity?, call: MethodCall, result: MethodChannel.Result) {
- this.result = result
- showAd(activity, null, call)
- }
-
- override fun onNoAD(error: AdError) {
- val msg =
- String.format(
- Locale.getDefault(),
- "onError, error code: %d, error msg: %s",
- error.getErrorCode(),
- error.getErrorMsg()
- )
- Log.i(TAG, "onError, adError=$msg")
- sendErrorEvent(error.getErrorCode(), error.getErrorMsg())
- this.result!!.success(ArrayList())
- }
-
- override fun onADLoaded(list: MutableList) {
- Log.i(TAG, "onADLoaded")
- val adResultList: MutableList = ArrayList()
-
- if (list.isEmpty()) {
- result!!.success(adResultList)
- return
- }
- for (adItem in list) {
- val key = adItem.hashCode()
- adResultList.add(key)
- FeedAdManager.getInstance()?.putAd(key, adItem)
- }
- // 添加广告事件
- sendEvent(AdEventAction.onAdLoaded)
- result!!.success(adResultList)
- }
-
- override fun onRenderFail(nativeExpressADView: NativeExpressADView) {
- Log.i(TAG, "onRenderFail")
- sendErrorEvent(-100, "onRenderFail")
- sendBroadcastEvent(nativeExpressADView, AdEventAction.onAdError)
- }
-
- private fun sendBroadcastEvent(adView: NativeExpressADView, event: String) {
- val intent = Intent()
- intent.setAction(UnionADConfig.KEY_FEED_VIEW + "_" + adView.hashCode())
- intent.putExtra("event", event)
- LocalBroadcastManager.getInstance(activity!!).sendBroadcast(intent)
- }
-
- override fun onRenderSuccess(nativeExpressADView: NativeExpressADView) {
- Log.i(TAG, "onRenderSuccess")
- sendEvent(AdEventAction.onAdPresent)
- sendBroadcastEvent(nativeExpressADView, AdEventAction.onAdPresent)
- }
-
- override fun onADExposure(nativeExpressADView: NativeExpressADView?) {
- Log.i(TAG, "onADExposure")
- sendEvent(AdEventAction.onAdExposure)
- }
-
- override fun onADClicked(nativeExpressADView: NativeExpressADView?) {
- Log.i(TAG, "onADClicked")
- sendEvent(AdEventAction.onAdClicked)
- }
-
- override fun onADClosed(nativeExpressADView: NativeExpressADView) {
- Log.i(TAG, "onADClosed")
- sendEvent(AdEventAction.onAdClosed)
- sendBroadcastEvent(nativeExpressADView, AdEventAction.onAdClosed)
- }
-
- override fun onADLeftApplication(p0: NativeExpressADView?) {}
-
- override fun loadAd(call: MethodCall?) {
- // 获取请求模板广告素材的尺寸
- val width: Int = call!!.argument("width")!!
- val height: Int = call.argument("height")!!
- val count: Int = call.argument("count")!!
- val ad = NativeExpressAD(activity, ADSize(width, height), posId, this)
- ad.loadAD(count)
- }
-}
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/load/FeedAdManager.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/load/FeedAdManager.kt
deleted file mode 100644
index d4d0e9c..0000000
--- a/android/src/main/kotlin/com/example/union_ad_ssgf/load/FeedAdManager.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.example.union_ad_ssgf.load
-
-import com.qq.e.ads.nativ.NativeExpressADView
-
-
-/**
- * 信息流广告管理
- */
-class FeedAdManager {
- private val TAG = FeedAdManager::class.java.getSimpleName()
-
- companion object {
- // 信息流广告管理类对象
- private var _instance: FeedAdManager? = null
-
- @Synchronized
- fun getInstance(): FeedAdManager? {
- if (_instance == null) {
- synchronized(FeedAdManager::class.java) { _instance = FeedAdManager() }
- }
- return _instance
- }
- }
-
- // 信息流广告列表
- private val feedAdList: MutableMap = HashMap()
-
- /**
- * 添加广告渲染对象
- *
- * @param key 广告缓存id
- * @param ad 广告渲染对象
- */
- fun putAd(key: Int, ad: NativeExpressADView) {
- feedAdList[key] = ad
- }
-
- /**
- * 获取广告渲染对象
- *
- * @param key 广告缓存 id
- * @return 广告渲染对象
- */
- fun getAd(key: Int): NativeExpressADView? {
- return feedAdList[key]
- }
-
- /**
- * 删除广告渲染对象
- *
- * @param key 广告缓存id
- * @return 广告渲染对象
- */
- fun removeAd(key: Int): NativeExpressADView? {
- return feedAdList.remove(key)
- }
-}
\ No newline at end of file
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/page/AdBannerView.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/page/AdBannerView.kt
deleted file mode 100644
index 8d71c96..0000000
--- a/android/src/main/kotlin/com/example/union_ad_ssgf/page/AdBannerView.kt
+++ /dev/null
@@ -1,97 +0,0 @@
-package com.example.union_ad_ssgf.page
-
-import android.content.Context
-import android.view.View
-import android.widget.FrameLayout
-import com.qq.e.ads.banner2.UnifiedBannerADListener
-import com.qq.e.ads.banner2.UnifiedBannerView
-import com.qq.e.comm.util.AdError
-import io.flutter.plugin.common.MethodCall
-import io.flutter.plugin.platform.PlatformView
-import java.util.Locale
-
-import android.util.Log;
-import com.example.union_ad_ssgf.PluginDelegate
-import com.example.union_ad_ssgf.event.AdEventAction
-
-class AdBannerView(
- context: Context,
- private var id: Int,
- creationParams: Map?,
- private var pluginDelegate: PluginDelegate?
-) : BaseAdPage(), PlatformView, UnifiedBannerADListener {
- private val TAG = AdBannerView::class.java.getSimpleName()
- private var frameLayout = FrameLayout(context)
- private var bv: UnifiedBannerView? = null
- private var params = creationParams
-
- init {
- val call = MethodCall("AdBannerView", creationParams)
- showAd(this.pluginDelegate!!.activity, id, call);
- }
-
- override fun loadAd(call: MethodCall?) {
- // 获取轮播时间间隔参数
- val interval = params!!["interval"] as Int
- // 加载广告 Banner
- bv = UnifiedBannerView(activity, posId, this)
- frameLayout!!.addView(bv)
- // 设置轮播时间间隔
- bv!!.setRefresh(interval)
- bv!!.loadAD()
- }
-
- override fun getView(): View? {
- return frameLayout;
- }
-
- override fun dispose() {
- disposeAd();
- }
-
- override fun onNoAD(error: AdError) {
- val msg = java.lang.String.format(
- Locale.getDefault(), "onNoAD, error code: %d, error msg: %s",
- error.getErrorCode(), error.getErrorMsg()
- )
- Log.e(TAG, msg)
- sendErrorEvent(error.getErrorCode(), error.getErrorMsg())
- disposeAd()
- }
-
- override fun onADReceive() {
- Log.i(TAG, "onADReceive");
- sendEvent(AdEventAction.onAdLoaded);
- }
-
- override fun onADExposure() {
- Log.i(TAG, "onADExposure");
- sendEvent(AdEventAction.onAdExposure);
- }
-
- override fun onADClosed() {
- Log.i(TAG, "onADClosed");
- sendEvent(AdEventAction.onAdClosed);
- disposeAd();
- }
-
- override fun onADClicked() {
- Log.i(TAG, "onADClicked");
- sendEvent(AdEventAction.onAdClicked);
- }
-
- override fun onADLeftApplication() {
- Log.i(TAG, "onADLeftApplication");
- }
-
- /**
- * 销毁广告
- */
- private fun disposeAd() {
- frameLayout!!.removeAllViews()
- if (bv != null) {
- bv!!.destroy()
- }
- }
-
-}
\ No newline at end of file
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/page/AdFeedView.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/page/AdFeedView.kt
deleted file mode 100644
index b0b139f..0000000
--- a/android/src/main/kotlin/com/example/union_ad_ssgf/page/AdFeedView.kt
+++ /dev/null
@@ -1,91 +0,0 @@
-package com.example.union_ad_ssgf.page
-
-import android.content.BroadcastReceiver
-import android.content.Context
-import android.content.Intent
-import android.content.IntentFilter
-import android.view.View
-import android.widget.FrameLayout
-import androidx.localbroadcastmanager.content.LocalBroadcastManager
-import com.example.union_ad_ssgf.PluginDelegate
-import com.example.union_ad_ssgf.config.UnionADConfig
-import com.example.union_ad_ssgf.event.AdEventAction
-import com.example.union_ad_ssgf.load.FeedAdManager
-import com.qq.e.ads.nativ.NativeExpressADView
-import io.flutter.plugin.common.MethodCall
-import io.flutter.plugin.platform.PlatformView
-
-class AdFeedView(
- context: Context,
- private var id: Int,
- private var creationParams: Map?,
- private var pluginDelegate: PluginDelegate?
-) : BaseAdPage(), PlatformView {
- private var frameLayout = FrameLayout(context)
- private var fad: NativeExpressADView? = null
- private var receiver: BroadcastReceiver? = null
-
- init {
- val call = MethodCall("AdFeedView", creationParams)
- showAd(this.pluginDelegate!!.activity, id, call)
- }
-
- override fun loadAd(call: MethodCall?) {
- val key = adId!!.toInt()
- regReceiver(key)
- fad = FeedAdManager.getInstance()!!.getAd(key)
- if (fad != null) {
- if (frameLayout.childCount > 0) {
- frameLayout.removeAllViews()
- }
- fad!!.render()
- frameLayout.addView(fad)
- }
- }
-
- override fun getView(): View? {
- return frameLayout
- }
-
- override fun dispose() {
- removeAd()
- }
-
- /**
- * 注册广播
- * @param key key
- */
- private fun regReceiver(key: Int) {
- // 注册广播
- receiver =
- object : BroadcastReceiver() {
- override fun onReceive(context: Context, intent: Intent) {
- val event = intent.getStringExtra("event")
- sendEvent(event)
- if (AdEventAction.onAdClosed == event || AdEventAction.onAdError == event) {
- this@AdFeedView.disposeAd()
- }
- }
- }
- val intentFilter = IntentFilter(UnionADConfig.KEY_FEED_VIEW + "_" + key)
- LocalBroadcastManager.getInstance(activity!!).registerReceiver(receiver!!, intentFilter)
- }
-
- /** 移除广告 */
- private fun removeAd() {
- frameLayout!!.removeAllViews()
- // 注销广播
- if (receiver != null) {
- LocalBroadcastManager.getInstance(activity!!).unregisterReceiver(receiver!!)
- }
- }
-
- /** 销毁广告 */
- private fun disposeAd() {
- removeAd()
- FeedAdManager.getInstance()!!.removeAd(adId!!.toInt())
- if (fad != null) {
- fad!!.destroy()
- }
- }
-}
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/page/AdSplashActivity.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/page/AdSplashActivity.kt
deleted file mode 100644
index 7ab1858..0000000
--- a/android/src/main/kotlin/com/example/union_ad_ssgf/page/AdSplashActivity.kt
+++ /dev/null
@@ -1,187 +0,0 @@
-package com.example.union_ad_ssgf.page
-
-import android.annotation.SuppressLint
-import android.os.Bundle
-import android.text.TextUtils
-import android.util.Log
-import android.view.KeyEvent
-import android.view.View
-import android.widget.FrameLayout
-import androidx.appcompat.app.AppCompatActivity
-import androidx.appcompat.widget.AppCompatImageView
-import com.example.union_ad_ssgf.R
-import com.example.union_ad_ssgf.config.UnionADConfig
-import com.example.union_ad_ssgf.event.AdErrorEvent
-import com.example.union_ad_ssgf.event.AdEvent
-import com.example.union_ad_ssgf.event.AdEventAction
-import com.example.union_ad_ssgf.event.AdEventHandler
-import com.qq.e.ads.splash.SplashAD
-import com.qq.e.ads.splash.SplashADListener
-import com.qq.e.comm.util.AdError
-
-
-/**
- * 开屏广告
- */
-class AdSplashActivity() : AppCompatActivity(), SplashADListener {
- private val TAG = AdSplashActivity::class.java.getSimpleName()
- /**
- * 广告容器
- */
- private var ad_container: FrameLayout? = null
-
- /**
- * 自定义品牌 logo
- */
- private var ad_logo: AppCompatImageView? = null
-
- /**
- * 广告位 id
- */
- private var posId: String? = null
-
- /**
- * 是否全屏
- */
- private var isFullScreen = false
-
- /**
- * 开屏广告
- */
- private var splashAD: SplashAD? = null
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_ad_splash);
- initView();
- initData();
- }
-
- /**
- * 初始化View
- */
- private fun initView() {
- ad_container = findViewById(R.id.splash_ad_container)
- ad_logo = findViewById(R.id.splash_ad_logo)
- }
-
- /**
- * 初始化数据
- */
- private fun initData() {
- // 获取参数
- posId = intent.getStringExtra(UnionADConfig.KEY_POSID)
- val logo = intent.getStringExtra(UnionADConfig.KEY_LOGO)
- val fetchDelay = intent.getDoubleExtra(UnionADConfig.KEY_FETCH_DELAY, 0.0)
- val absFetchDelay = (fetchDelay * 1000).toInt()
- isFullScreen = TextUtils.isEmpty(logo)
- // 创建开屏广告
- splashAD = SplashAD(this, posId, this, absFetchDelay)
- if (isFullScreen) {
- // logo 为空则加载全屏广告
- ad_logo!!.setVisibility(View.GONE)
- splashAD!!.fetchFullScreenAdOnly()
- } else {
- // 加载 logo
- val resId: Int = getMipmapId(logo!!)
- if (resId > 0) {
- ad_logo!!.setVisibility(View.VISIBLE)
- ad_logo!!.setImageResource(resId)
- }
- // 加载广告
- splashAD!!.fetchAdOnly()
- }
- }
-
- /**
- * 广告关闭时调用,可能是用户关闭或者展示时间到。此时一般需要跳过开屏的 Activity,进入应用内容页面
- */
- override fun onADDismissed() {
- Log.d(TAG, "onADDismissed")
- finishPage()
- AdEventHandler.getInstance()?.sendEvent(AdEvent(posId, "", 1, AdEventAction.onAdClosed));
- }
-
- /**
- * 广告加载或展示过程中出错,AdError中包含了错误码和错误描述,具体错误码内容可参考错误码部分
- */
- override fun onNoAD(adError: AdError) {
- Log.d(TAG, "onNoAD adError:" + adError.errorMsg);
- finishPage()
- AdEventHandler.getInstance()!!
- .sendEvent(AdErrorEvent(posId, "", 1, adError.errorCode, adError.errorMsg));
- }
-
- /**
- * 广告成功展示时调用,成功展示不等于有效展示(比如广告容器高度不够)
- */
- override fun onADPresent() {
- Log.d(TAG, "onADPresent")
- AdEventHandler.getInstance()!!.sendEvent(AdEvent(posId, "", 1, AdEventAction.onAdPresent))
- }
-
- /**
- * 广告被点击时调用,不代表满足计费条件(如点击时网络异常)
- */
- override fun onADClicked() {
- Log.d(TAG, "onADClicked")
- AdEventHandler.getInstance()!!.sendEvent(AdEvent(posId, "", 1, AdEventAction.onAdClicked))
- }
-
- /**
- * 倒计时回调,返回广告还将被展示的剩余时间,单位是 ms
- */
- override fun onADTick(millisUntilFinished: Long) {
- Log.d(TAG, "onADTick millisUntilFinished:$millisUntilFinished");
- }
-
- /**
- * 广告曝光时调用
- */
- override fun onADExposure() {
- Log.d(TAG, "onADExposure")
- AdEventHandler.getInstance()!!.sendEvent(AdEvent(posId, "", 1, AdEventAction.onAdExposure))
- }
-
- /**
- * 广告加载成功的回调,在fetchAdOnly的情况下,表示广告拉取成功可以显示了。
- * 广告需要在SystemClock.elapsedRealtime (UnionADConfig.KEY_POSID)
- this.adId = call.argument(UnionADConfig.KEY_ADID)
- loadAd(call)
- }
-
- /**
- * 加载广告
- * @param call 方法调用
- */
- abstract fun loadAd(call: MethodCall?)
-
- /**
- * 发送广告事件
- * @param event 广告事件
- */
- protected fun sendEvent(event: AdEvent?) {
- AdEventHandler.getInstance()?.sendEvent(event)
- }
-
- /**
- * 发送广告事件
- *
- * @param action 操作
- */
- protected fun sendEvent(action: String?) {
- sendEvent(AdEvent(posId, adId, viewId, action))
- }
-
- /**
- * 发送错误事件
- *
- * @param errCode 错误码
- * @param errMsg 错误事件
- */
- protected fun sendErrorEvent(errCode: Int, errMsg: String?) {
- sendEvent(AdErrorEvent(posId, adId, viewId, errCode, errMsg))
- }
-}
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/page/NativeViewFactory.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/page/NativeViewFactory.kt
deleted file mode 100644
index dcb9a4d..0000000
--- a/android/src/main/kotlin/com/example/union_ad_ssgf/page/NativeViewFactory.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.example.union_ad_ssgf.page
-
-import android.content.Context
-import com.example.union_ad_ssgf.PluginDelegate
-import com.example.union_ad_ssgf.config.UnionADConfig
-import io.flutter.plugin.common.StandardMessageCodec
-import io.flutter.plugin.platform.PlatformView
-import io.flutter.plugin.platform.PlatformViewFactory
-
-/**
- * View 名字
- * @param viewName: 插件代理类
- */
-class NativeViewFactory(
- private val viewName: String,
- private val pluginDelegate: PluginDelegate
-) :
- PlatformViewFactory(StandardMessageCodec.INSTANCE) {
-
- override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
- val creationParams = args as Map
- return if (viewName == UnionADConfig.KEY_BANNER_VIEW) {
- AdBannerView(context, viewId, creationParams, pluginDelegate)
- } else {
- AdFeedView(context, viewId, creationParams, pluginDelegate)
- }
- }
-
-}
\ No newline at end of file
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/page/RewardVideoPage.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/page/RewardVideoPage.kt
deleted file mode 100644
index 6f6aeb1..0000000
--- a/android/src/main/kotlin/com/example/union_ad_ssgf/page/RewardVideoPage.kt
+++ /dev/null
@@ -1,138 +0,0 @@
-package com.example.union_ad_ssgf.page
-
-import android.util.Log
-import com.example.union_ad_ssgf.event.AdEventAction
-import com.example.union_ad_ssgf.event.AdRewardEvent
-import com.qq.e.ads.rewardvideo.RewardVideoAD
-import com.qq.e.ads.rewardvideo.RewardVideoADListener
-import com.qq.e.ads.rewardvideo.ServerSideVerificationOptions
-import com.qq.e.comm.util.AdError
-import io.flutter.plugin.common.MethodCall
-import java.util.Locale
-
-/**
- * 激励视频页面
- */
-class RewardVideoPage() : BaseAdPage(), RewardVideoADListener {
- private val TAG = RewardVideoPage::class.java.getSimpleName()
- /**
- * 激励广告对象
- */
- private lateinit var rewardVideoAD: RewardVideoAD
-
- /**
- * 设置激励视频服务端验证的自定义信息
- */
- private lateinit var customData: String
-
- /**
- * 设置服务端验证的用户信息
- */
- private lateinit var userId: String
-
- /**
- * 加载激励视频广告,加载成功则调用回调RewardVideoADListener.onADLoad(),
- * 加载失败则会调用RewardVideoADListener.onError(AdError error)
- */
- override fun loadAd(call: MethodCall?) {
- /**
- * 获取对应参数
- */
- val playMuted: Boolean = call!!.argument("playMuted")!!
- customData = call.argument("customData")!!
- userId = call.argument("userId")!!
-
- // 1. 初始化激励视频广告
- rewardVideoAD = RewardVideoAD(activity, posId, this, !playMuted)
-
- // 2. 设置服务端验证信息
- val options = ServerSideVerificationOptions.Builder()
- .setCustomData(customData)
- .setUserId(userId) // 设置服务端验证的用户信息
- .build()
-
- // 3. 服务端验证信息
- rewardVideoAD.setServerSideVerificationOptions(options)
-
- // 4. 加载激励视频广告
- rewardVideoAD.loadAD()
- }
-
- /**
- * 广告加载成功,可在此回调后进行广告展示
- **/
- override fun onADLoad() {
- Log.i(TAG, "onADLoad")
- rewardVideoAD.showAD()
- sendEvent(AdEventAction.onAdLoaded)
- }
-
- /**
- * 视频素材缓存成功,可在此回调后进行广告展示
- */
- override fun onVideoCached() {
- Log.i(TAG, "onVideoCached")
- }
-
- /**
- * 激励视频广告页面展示
- */
- override fun onADShow() {
- Log.i(TAG, "onADShow")
- sendEvent(AdEventAction.onAdPresent)
- }
-
- /**
- * 激励视频广告曝光
- */
- override fun onADExpose() {
- Log.i(TAG, "onADExpose")
- sendEvent(AdEventAction.onAdExposure)
- }
-
- /**
- * 激励视频触发激励(观看视频大于一定时长或者视频播放完毕)
- * @param map 若选择了服务端验证,可以通过 ServerSideVerificationOptions#TRANS_ID 键从 map 中获取此次交易的 id;若未选择服务端验证,则不需关注 map 参数。
- */
- override fun onReward(map: MutableMap?) {
- val transId = map!![ServerSideVerificationOptions.TRANS_ID] as String?
- Log.i(TAG, "onReward $transId") // 获取服务端验证的唯一 ID
- sendEvent(AdRewardEvent(posId,"",1,AdEventAction.onAdReward, transId!!, customData, userId))
- }
-
- /**
- * 激励视频广告被点击
- */
- override fun onADClick() {
- Log.i(TAG, "onADClick")
- sendEvent(AdEventAction.onAdClicked)
- }
-
- /**
- * 激励视频广告被关闭
- */
- override fun onVideoComplete() {
- Log.i(TAG, "onVideoComplete")
- }
-
- /**
- * 激励视频广告被关闭
- */
- override fun onADClose() {
- Log.i(TAG, "onADClose")
- sendEvent(AdEventAction.onAdClosed)
- }
-
- /**
- * 广告流程出错
- */
- override fun onError(error: AdError) {
- val msg = java.lang.String.format(
- Locale.getDefault(),
- "onError, error code: %d, error msg: %s",
- error.errorCode, error.errorMsg,
- )
- Log.i(TAG, "onError, adError=$msg")
- sendErrorEvent(error.errorCode, error.errorMsg)
- }
-}
\ No newline at end of file
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/rewardvideoad/RewardVideoAd.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/rewardvideoad/RewardVideoAd.kt
new file mode 100644
index 0000000..5b044b2
--- /dev/null
+++ b/android/src/main/kotlin/com/example/union_ad_ssgf/rewardvideoad/RewardVideoAd.kt
@@ -0,0 +1,182 @@
+package com.example.union_ad_ssgf.rewardvideoad
+
+import android.annotation.SuppressLint
+import android.content.Context
+import com.example.union_ad_ssgf.DownloadConfirmHelper
+import com.example.union_ad_ssgf.LogUtil
+import com.example.union_ad_ssgf.UnionAdSsgfEventPlugin
+import com.qq.e.ads.rewardvideo.RewardVideoAD
+import com.qq.e.ads.rewardvideo.RewardVideoADListener
+import com.qq.e.ads.rewardvideo.ServerSideVerificationOptions
+import com.qq.e.comm.pi.IBidding
+import com.qq.e.comm.util.AdError
+
+
+@SuppressLint("StaticFieldLeak")
+object RewardVideoAd {
+ private val TAG = "RewardVideoAd"
+
+ private lateinit var context: Context
+ private var rewardVideoAD: RewardVideoAD? = null
+
+ private var codeId: String? = null
+ private var userID: String = ""
+ private var rewardName: String = ""
+ private var rewardAmount: Int = 0
+ private var customData: String = ""
+ private var downloadConfirm: Boolean = false
+ private var videoMuted: Boolean = false
+
+ //是否开启竞价
+ private var isBidding: Boolean = false
+
+ fun init(context: Context, params: Map<*, *>) {
+ this.context = context
+ this.codeId = params["androidId"] as String
+ this.userID = params["userID"] as String
+ this.rewardName = params["rewardName"] as String
+ this.rewardAmount = params["rewardAmount"] as Int
+ this.customData = params["customData"] as String
+ this.downloadConfirm = params["downloadConfirm"] as Boolean
+ this.isBidding = params["isBidding"] as Boolean
+ this.videoMuted = params["videoMuted"] as Boolean
+ loadRewardVideoAd()
+ }
+
+ private fun loadRewardVideoAd() {
+ rewardVideoAD = RewardVideoAD(context, codeId, rewardVideoADListener,videoMuted)
+ val options = ServerSideVerificationOptions.Builder()
+ .setUserId(userID)
+ .setCustomData(customData)
+ .build()
+ rewardVideoAD?.setServerSideVerificationOptions(options)
+ rewardVideoAD?.loadAD()
+ }
+
+ fun showAd(params: Map<*, *>) {
+ if (rewardVideoAD == null) {
+ val map: MutableMap =
+ mutableMapOf("adType" to "rewardAd", "onAdMethod" to "onUnReady")
+ UnionAdSsgfEventPlugin.sendContent(map)
+ return
+ }
+ //是否为竞价模式
+ if (isBidding) {
+ val isSuccess: Boolean = params["isSuccess"] as Boolean
+ //是否成功
+ if (isSuccess) {
+ rewardVideoAD?.sendWinNotification(
+ mutableMapOf(
+ //对应值为竞胜出价,类型为Integer
+ IBidding.EXPECT_COST_PRICE to params["expectCostPrice"],
+ //对应值为最大竞败方出价,类型为Integer
+ IBidding.HIGHEST_LOSS_PRICE to params["highestLossPrice"],
+ )
+ )
+ rewardVideoAD?.showAD()
+ } else {
+ rewardVideoAD?.sendLossNotification(
+ mutableMapOf(
+ //值为本次竞胜方出价(单位:分),类型为Integer。选填
+ IBidding.WIN_PRICE to params["winPrice"],
+ //值为优量汇广告竞败原因,类型为Integer。必填
+ IBidding.LOSS_REASON to params["lossReason"],
+ //值为本次竞胜方渠道ID,类型为Integer。必填。
+ IBidding.ADN_ID to params["adnId"],
+ )
+ )
+ }
+ } else {
+ rewardVideoAD?.showAD()
+ }
+
+ }
+
+ private var rewardVideoADListener = object : RewardVideoADListener {
+ override fun onADLoad() {
+ LogUtil.e("$TAG 激励广告加载成功")
+ if (downloadConfirm) {
+ rewardVideoAD?.setDownloadConfirmListener(DownloadConfirmHelper.DOWNLOAD_CONFIRM_LISTENER)
+ }
+ }
+
+ override fun onVideoCached() {
+ LogUtil.e("$TAG 激励广告视频素材缓存成功")
+ if (isBidding) {
+ val map: MutableMap =
+ mutableMapOf(
+ "adType" to "rewardAd",
+ "onAdMethod" to "onECPM",
+ "ecpmLevel" to rewardVideoAD?.ecpmLevel,
+ "ecpm" to rewardVideoAD?.ecpm
+ )
+ UnionAdSsgfEventPlugin.sendContent(map)
+ } else {
+ val map: MutableMap =
+ mutableMapOf("adType" to "rewardAd", "onAdMethod" to "onReady")
+ UnionAdSsgfEventPlugin.sendContent(map)
+ }
+ }
+
+ override fun onADShow() {
+ LogUtil.e("$TAG 激励视频广告页面展示")
+ val map: MutableMap =
+ mutableMapOf("adType" to "rewardAd", "onAdMethod" to "onShow")
+ UnionAdSsgfEventPlugin.sendContent(map)
+ }
+
+ override fun onADExpose() {
+ LogUtil.e("$TAG 激励视频广告曝光")
+ val map: MutableMap =
+ mutableMapOf("adType" to "rewardAd", "onAdMethod" to "onExpose")
+ UnionAdSsgfEventPlugin.sendContent(map)
+ }
+
+ override fun onReward(p0: MutableMap?) {
+ LogUtil.e("$TAG 激励视频广告激励发放 $p0")
+
+ val map: MutableMap = mutableMapOf(
+ "adType" to "rewardAd",
+ "onAdMethod" to "onVerify",
+ "transId" to p0!!["transId"],
+ "rewardName" to rewardName,
+ "rewardAmount" to rewardAmount
+ )
+ UnionAdSsgfEventPlugin.sendContent(map)
+ }
+
+ override fun onADClick() {
+ LogUtil.e("$TAG 激励视频广告被点击")
+ val map: MutableMap =
+ mutableMapOf("adType" to "rewardAd", "onAdMethod" to "onClick")
+ UnionAdSsgfEventPlugin.sendContent(map)
+ }
+
+ override fun onVideoComplete() {
+ LogUtil.e("$TAG 激励视频广告视频素材播放完毕")
+ val map: MutableMap =
+ mutableMapOf("adType" to "rewardAd", "onAdMethod" to "onFinish")
+ UnionAdSsgfEventPlugin.sendContent(map)
+ }
+
+ override fun onADClose() {
+ LogUtil.e("$TAG 激励视频广告被关闭")
+ val map: MutableMap =
+ mutableMapOf("adType" to "rewardAd", "onAdMethod" to "onClose")
+ UnionAdSsgfEventPlugin.sendContent(map)
+ rewardVideoAD = null
+ }
+
+ override fun onError(p0: AdError?) {
+ LogUtil.e("$TAG 广告流程出错 ${p0?.errorCode} ${p0?.errorMsg}")
+ val map: MutableMap = mutableMapOf(
+ "adType" to "rewardAd",
+ "onAdMethod" to "onFail",
+ "code" to p0?.errorCode,
+ "message" to p0?.errorMsg
+ )
+ UnionAdSsgfEventPlugin.sendContent(map)
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/splashad/SplashAdView.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/splashad/SplashAdView.kt
new file mode 100644
index 0000000..cf29500
--- /dev/null
+++ b/android/src/main/kotlin/com/example/union_ad_ssgf/splashad/SplashAdView.kt
@@ -0,0 +1,151 @@
+package com.example.union_ad_ssgf.splashad
+
+import android.app.Activity
+import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import com.example.union_ad_ssgf.DownloadConfirmHelper
+import com.example.union_ad_ssgf.UnionAdSsgfConfig
+import com.example.union_ad_ssgf.LogUtil
+import com.qq.e.ads.splash.SplashAD
+import com.qq.e.ads.splash.SplashADListener
+import com.qq.e.comm.pi.IBidding
+import com.qq.e.comm.util.AdError
+import io.flutter.plugin.common.BinaryMessenger
+import io.flutter.plugin.common.MethodCall
+import io.flutter.plugin.common.MethodChannel
+import io.flutter.plugin.platform.PlatformView
+
+
+internal class SplashAdView(
+ var activity: Activity,
+ messenger: BinaryMessenger,
+ id: Int,
+ params: Map
+) :
+ PlatformView, SplashADListener , MethodChannel.MethodCallHandler {
+
+ private var mContainer: FrameLayout? = null
+ private var channel: MethodChannel?
+
+ private var splashAD: SplashAD? = null
+
+ //广告所需参数
+ private var codeId: String = params["androidId"] as String
+ private var fetchDelay: Int = params["fetchDelay"] as Int
+ private var downloadConfirm: Boolean = params["downloadConfirm"] as Boolean
+ //是否开启竞价
+ private var isBidding: Boolean = params["isBidding"] as Boolean
+
+ init {
+ mContainer = FrameLayout(activity)
+ mContainer?.layoutParams?.width = ViewGroup.LayoutParams.WRAP_CONTENT
+ mContainer?.layoutParams?.height = ViewGroup.LayoutParams.WRAP_CONTENT
+ channel = MethodChannel(messenger, UnionAdSsgfConfig.splashAdView + "_" + id)
+ channel?.setMethodCallHandler(this)
+ loadSplashAd()
+ }
+
+ private fun loadSplashAd() {
+ splashAD = SplashAD(activity, codeId, this, fetchDelay)
+ mContainer?.removeAllViews()
+ splashAD?.fetchAdOnly()
+ }
+
+
+ override fun getView(): View {
+ return mContainer!!
+ }
+
+ /*************开屏广告回调******************/
+ //广告关闭时调用,可能是用户关闭或者展示时间到。此时一般需要跳过开屏的 Activity,进入应用内容页面
+ override fun onADDismissed() {
+ LogUtil.e("开屏广告关闭")
+ channel?.invokeMethod("onClose", "")
+ }
+
+ //广告加载失败,error 对象包含了错误码和错误信息,错误码的详细内容可以参考文档第5章
+ override fun onNoAD(p0: AdError?) {
+ LogUtil.e("开屏广告加载失败 ${p0?.errorCode} ${p0?.errorMsg}")
+ var map: MutableMap = mutableMapOf("code" to p0?.errorCode, "message" to p0?.errorMsg)
+ channel?.invokeMethod("onFail", map)
+ }
+
+ //广告成功展示时调用,成功展示不等于有效展示(比如广告容器高度不够)
+ override fun onADPresent() {
+ LogUtil.e("开屏广告成功展示")
+ channel?.invokeMethod("onShow", "")
+ }
+
+ //广告被点击时调用,不代表满足计费条件(如点击时网络异常)
+ override fun onADClicked() {
+ LogUtil.e("开屏广告被点击")
+ channel?.invokeMethod("onClick", "")
+ }
+
+ //倒计时回调,返回广告还将被展示的剩余时间,单位是 ms
+ override fun onADTick(p0: Long) {
+ LogUtil.e("开屏广告倒计时回调 $p0")
+ channel?.invokeMethod("onADTick", p0)
+ }
+
+ //广告曝光时调用
+ override fun onADExposure() {
+ LogUtil.e("开屏广告曝光")
+ channel?.invokeMethod("onExpose", "")
+ }
+
+ //广告加载成功的回调,在fetchAdOnly的情况下,
+ // 表示广告拉取成功可以显示了。广告需要在SystemClock.elapsedRealtime {
+ var arguments = call.arguments as Map<*, *>
+ splashAD?.sendWinNotification(mutableMapOf(
+ //对应值为竞胜出价,类型为Integer
+ IBidding.EXPECT_COST_PRICE to arguments["expectCostPrice"],
+ //对应值为最大竞败方出价,类型为Integer
+ IBidding.HIGHEST_LOSS_PRICE to arguments["highestLossPrice"],
+ ))
+ //展示banner
+ splashAD?.showAd(mContainer)
+ }
+ //竞价失败
+ "biddingFail" -> {
+ var arguments = call.arguments as Map<*, *>
+ splashAD?.sendLossNotification(mutableMapOf(
+ //值为本次竞胜方出价(单位:分),类型为Integer。选填
+ IBidding.WIN_PRICE to arguments["winPrice"],
+ //值为优量汇广告竞败原因,类型为Integer。必填
+ IBidding.LOSS_REASON to arguments["lossReason"],
+ //值为本次竞胜方渠道ID,类型为Integer。必填。
+ IBidding.ADN_ID to arguments["adnId"],
+ ))
+ }
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/splashad/SplashAdViewFactory.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/splashad/SplashAdViewFactory.kt
new file mode 100644
index 0000000..13b0625
--- /dev/null
+++ b/android/src/main/kotlin/com/example/union_ad_ssgf/splashad/SplashAdViewFactory.kt
@@ -0,0 +1,18 @@
+package com.example.union_ad_ssgf.splashad
+
+import android.app.Activity
+import android.content.Context
+import com.example.union_ad_ssgf.bannerad.BannerAdView
+import io.flutter.plugin.common.BinaryMessenger
+import io.flutter.plugin.common.StandardMessageCodec
+import io.flutter.plugin.platform.PlatformView
+import io.flutter.plugin.platform.PlatformViewFactory
+
+class SplashAdViewFactory (private val messenger: BinaryMessenger, private val activity: Activity) : PlatformViewFactory(
+ StandardMessageCodec.INSTANCE) {
+
+ override fun create(context: Context?, viewId: Int, args: Any?): PlatformView {
+ val params = args as Map
+ return SplashAdView(activity,messenger, viewId, params)
+ }
+}
\ No newline at end of file
diff --git a/android/src/main/res/anim/download_confirm_dialog_slide_right_in.xml b/android/src/main/res/anim/download_confirm_dialog_slide_right_in.xml
new file mode 100644
index 0000000..7d5eb9c
--- /dev/null
+++ b/android/src/main/res/anim/download_confirm_dialog_slide_right_in.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/src/main/res/anim/download_confirm_dialog_slide_up.xml b/android/src/main/res/anim/download_confirm_dialog_slide_up.xml
new file mode 100644
index 0000000..914107a
--- /dev/null
+++ b/android/src/main/res/anim/download_confirm_dialog_slide_up.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/src/main/res/drawable/download_confirm_background_confirm.xml b/android/src/main/res/drawable/download_confirm_background_confirm.xml
new file mode 100644
index 0000000..eb2bdf9
--- /dev/null
+++ b/android/src/main/res/drawable/download_confirm_background_confirm.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/src/main/res/drawable/download_confirm_background_landscape.xml b/android/src/main/res/drawable/download_confirm_background_landscape.xml
new file mode 100644
index 0000000..7a3bee2
--- /dev/null
+++ b/android/src/main/res/drawable/download_confirm_background_landscape.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/src/main/res/drawable/download_confirm_background_portrait.xml b/android/src/main/res/drawable/download_confirm_background_portrait.xml
new file mode 100644
index 0000000..148b739
--- /dev/null
+++ b/android/src/main/res/drawable/download_confirm_background_portrait.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/src/main/res/drawable/ic_download_confirm_close.xml b/android/src/main/res/drawable/ic_download_confirm_close.xml
new file mode 100644
index 0000000..f37d2a6
--- /dev/null
+++ b/android/src/main/res/drawable/ic_download_confirm_close.xml
@@ -0,0 +1,12 @@
+
+
+
diff --git a/android/src/main/res/layout/download_confirm_dialog.xml b/android/src/main/res/layout/download_confirm_dialog.xml
new file mode 100644
index 0000000..1cd1832
--- /dev/null
+++ b/android/src/main/res/layout/download_confirm_dialog.xml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/src/main/res/values/styles.xml b/android/src/main/res/values/styles.xml
new file mode 100644
index 0000000..56766ac
--- /dev/null
+++ b/android/src/main/res/values/styles.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
diff --git a/example/integration_test/plugin_integration_test.dart b/example/integration_test/plugin_integration_test.dart
index 8b2661f..70b4eb2 100644
--- a/example/integration_test/plugin_integration_test.dart
+++ b/example/integration_test/plugin_integration_test.dart
@@ -6,20 +6,17 @@
// For more information about Flutter integration tests, please see
// https://docs.flutter.dev/cookbook/testing/integration/introduction
-
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
+import 'package:union_ad_ssgf/flutter_union_ad.dart';
-import 'package:union_ad_ssgf/union_ad_ssgf.dart';
+// import 'package:union_ad_ssgf/f.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('getPlatformVersion test', (WidgetTester tester) async {
- final UnionAdSsgf plugin = UnionAdSsgf();
- final String? version = await plugin.getPlatformVersion();
- // The version string depends on the host platform running the test, so
- // just assert that some non-empty string is returned.
- expect(version?.isNotEmpty, true);
+ final String version = await FlutterUnionAd.getSDKVersion();
+ expect(version.isNotEmpty, true);
});
}
diff --git a/example/lib/home_page.dart b/example/lib/home_page.dart
index 81679a3..c065e94 100644
--- a/example/lib/home_page.dart
+++ b/example/lib/home_page.dart
@@ -2,9 +2,7 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
-import 'package:union_ad_ssgf/event/ad_event_handler.dart';
import 'package:union_ad_ssgf_example/ads_config.dart';
-import 'package:union_ad_ssgf/union_ad_ssgf.dart';
// 结果信息
String _result = '';
@@ -170,24 +168,11 @@ class _HomePageState extends State {
setState(() {
_adEvent = '设置成功';
});
- UnionAdSsgf.onEventListener((event) {
- _adEvent = 'adId:${event.adId} action:${event.action}';
- if (event is AdErrorEvent) {
- // 错误事件
- _adEvent += ' errCode:${event.errCode} errMsg:${event.errMsg}';
- } else if (event is AdRewardEvent) {
- // 激励事件
- _adEvent +=
- ' transId:${event.transId} customData:${event.customData} userId:${event.userId}';
- }
- print('onEventListener:$_adEvent');
- setState(() {});
- });
}
/// 请求应用跟踪透明度授权
Future requestIDFA() async {
- bool result = await UnionAdSsgf.requestIDFA;
+ bool result = false;
_adEvent = '请求广告标识符:$result';
setState(() {});
}
@@ -195,7 +180,7 @@ class _HomePageState extends State {
/// 设置个性化广告
/// [state] 0:不限制 1:限制
Future setPersonalizedAd(int state) async {
- bool result = await UnionAdSsgf.setPersonalizedState(state);
+ bool result = false;
_adEvent = '设置个性化广告:$result';
setState(() {});
}
@@ -206,33 +191,13 @@ class _HomePageState extends State {
bool showFullScreenVideo = false,
bool showRewardVideo = false,
}) async {
- // try {
- // bool result = await UnionAdSsgf.showInterstitialAd(
- // posId,
- // showPopup: false,
- // showFullScreenVideo: showFullScreenVideo,
- // showRewardVideo: showRewardVideo,
- // autoPlayMuted: false,
- // autoPlayOnWifi: false,
- // userId: 'userId',
- // customData: 'showInterstitialAd customData',
- // );
- // _result = "展示插屏广告${result ? '成功' : '失败'}";
- // } on PlatformException catch (e) {
- // _result = "展示插屏广告失败 code:${e.code} msg:${e.message} details:${e.details}";
- // }
setState(() {});
}
/// 展示激励视频广告
Future showRewardVideoAd() async {
try {
- bool result = await UnionAdSsgf.showRewardVideoAd(
- AdsConfig.rewardVideoId,
- playMuted: false,
- customData: 'showRewardVideoAd customData',
- userId: 'userId',
- );
+ bool result = false;
_result = "展示激励视频广告${result ? '成功' : '失败'}";
} on PlatformException catch (e) {
_result =
@@ -246,11 +211,7 @@ class _HomePageState extends State {
/// [logo] 展示如果传递则展示logo,不传递不展示
Future showSplashAd([String? logo]) async {
try {
- bool result = await UnionAdSsgf.showSplashAd(
- AdsConfig.splashId,
- logo: logo,
- fetchDelay: 3,
- );
+ bool result = false;
_result = "展示开屏广告${result ? '成功' : '失败'}";
} on PlatformException catch (e) {
_result = "展示开屏广告失败 code:${e.code} msg:${e.message} details:${e.details}";
diff --git a/example/lib/main.dart b/example/lib/main.dart
index 72b2bba..f5927b2 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -1,10 +1,6 @@
import 'package:flutter/material.dart';
+import 'package:union_ad_ssgf/flutter_union_ad.dart';
import 'dart:async';
-
-import 'package:union_ad_ssgf/union_ad_ssgf.dart';
-import 'package:union_ad_ssgf/event/ad_error_event.dart';
-import 'package:union_ad_ssgf/event/ad_reward_event.dart';
-import 'package:union_ad_ssgf_example/ads_config.dart';
import 'package:union_ad_ssgf_example/home_page.dart';
void main() {
@@ -30,31 +26,27 @@ class _MyAppState extends State {
@override
Widget build(BuildContext context) {
- return MaterialApp(
+ return const MaterialApp(
home: HomePage(),
);
}
/// 初始化广告 SDK
Future init() async {
- bool result = await UnionAdSsgf.initAd(AdsConfig.appId);
+ bool result = await FlutterUnionAd.register(
+ androidId: "1200310001",
+ // androidId
+ iosId: "1202937154",
+ // iosId
+ debug: true,
+ // 是否显示日志log
+ personalized: FlutterTencentadPersonalized.show,
+ // 是否显示个性化推荐广告
+ channelId: FlutterTencentadChannel.tencent, //渠道id
+ );
+ print("------>>>> $result");
print("----->> result: $result");
debugPrint("广告SDK 初始化${result ? '成功' : '失败'}");
return result;
}
-
- /// 设置广告监听
- Future setAdEvent() async {
- UnionAdSsgf.onEventListener((event) {
- debugPrint('adId:${event.adId} action:${event.action}');
- if (event is AdErrorEvent) {
- // 错误事件
- debugPrint(' errCode:${event.errCode} errMsg:${event.errMsg}');
- } else if (event is AdRewardEvent) {
- // 激励事件
- debugPrint(
- ' transId:${event.transId} userId:${event.userId} customData:${event.customData}');
- }
- });
- }
}
diff --git a/example/macos/Runner/AppDelegate.swift b/example/macos/Runner/AppDelegate.swift
index d53ef64..8e02df2 100644
--- a/example/macos/Runner/AppDelegate.swift
+++ b/example/macos/Runner/AppDelegate.swift
@@ -1,7 +1,7 @@
import Cocoa
import FlutterMacOS
-@NSApplicationMain
+@main
class AppDelegate: FlutterAppDelegate {
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
diff --git a/lib/banner/banner_ad_view.dart b/lib/banner/banner_ad_view.dart
new file mode 100644
index 0000000..96ec2e3
--- /dev/null
+++ b/lib/banner/banner_ad_view.dart
@@ -0,0 +1,150 @@
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:union_ad_ssgf/flutter_union_ad.dart';
+
+class BannerAdView extends StatefulWidget {
+ final String androidId;
+ final String iosId;
+ final double viewWidth;
+ final double viewHeight;
+ final FlutterUnionAdBannerCallBack? callBack;
+ final bool downloadConfirm;
+ final bool isBidding;
+ final FlutterUnioAdBiddingController? bidding;
+
+ const BannerAdView({
+ Key? key,
+ required this.androidId,
+ required this.iosId,
+ required this.viewWidth,
+ required this.viewHeight,
+ this.callBack,
+ required this.downloadConfirm,
+ required this.isBidding,
+ this.bidding,
+ }) : super(key: key);
+
+ @override
+ State createState() => _BannerAdViewState();
+}
+
+class _BannerAdViewState extends State {
+ final String _viewType = "com.example.union_ad_ssgf/BannerAdView";
+
+ MethodChannel? _channel;
+
+ //广告是否显示
+ bool _isShowAd = true;
+
+ double _width = 0;
+ double _height = 0;
+
+ @override
+ void initState() {
+ super.initState();
+ _width = widget.viewWidth;
+ _height = widget.viewHeight;
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ if (!_isShowAd) {
+ return Container();
+ }
+ if (defaultTargetPlatform == TargetPlatform.android) {
+ return SizedBox(
+ width: _width,
+ height: _height,
+ child: AndroidView(
+ viewType: _viewType,
+ creationParams: {
+ "androidId": widget.androidId,
+ "viewWidth": widget.viewWidth,
+ "viewHeight": widget.viewHeight,
+ "downloadConfirm": widget.downloadConfirm,
+ "isBidding": widget.isBidding,
+ },
+ onPlatformViewCreated: _registerChannel,
+ creationParamsCodec: const StandardMessageCodec(),
+ ),
+ );
+ } else if (defaultTargetPlatform == TargetPlatform.iOS) {
+ return SizedBox(
+ width: _width,
+ height: _height,
+ child: UiKitView(
+ viewType: _viewType,
+ creationParams: {
+ "iosId": widget.iosId,
+ "viewWidth": widget.viewWidth,
+ "viewHeight": widget.viewHeight,
+ "isBidding": widget.isBidding,
+ },
+ onPlatformViewCreated: _registerChannel,
+ creationParamsCodec: const StandardMessageCodec(),
+ ),
+ );
+ } else {
+ return Container();
+ }
+ }
+
+ //注册cannel
+ void _registerChannel(int id) {
+ _channel = MethodChannel("${_viewType}_$id");
+ _channel?.setMethodCallHandler(_platformCallHandler);
+ widget.bidding?.init(_channel);
+ }
+
+ //监听原生view传值
+ Future _platformCallHandler(MethodCall call) async {
+ print("${call.method} ==== ${call.arguments}");
+ switch (call.method) {
+ //显示广告
+ case FlutterTencentadMethod.onShow:
+ Map map = call.arguments;
+ if (mounted) {
+ setState(() {
+ _width = map["width"];
+ _height = map["height"];
+ _isShowAd = true;
+ });
+ }
+ widget.callBack?.onShow!();
+ break;
+ //广告加载失败
+ case FlutterTencentadMethod.onFail:
+ if (mounted) {
+ setState(() {
+ _isShowAd = false;
+ });
+ }
+ Map map = call.arguments;
+ widget.callBack?.onFail!(map["code"], map["message"]);
+ break;
+ //点击
+ case FlutterTencentadMethod.onClick:
+ widget.callBack?.onClick!();
+ break;
+ //曝光
+ case FlutterTencentadMethod.onExpose:
+ widget.callBack?.onExpose!();
+ break;
+ //关闭
+ case FlutterTencentadMethod.onClose:
+ if (mounted) {
+ setState(() {
+ _isShowAd = false;
+ });
+ }
+ widget.callBack?.onClose!();
+ break;
+ //竞价
+ case FlutterTencentadMethod.onECPM:
+ Map map = call.arguments;
+ widget.callBack?.onECPM!(map["ecpmLevel"], map["ecpm"]);
+ break;
+ }
+ }
+}
diff --git a/lib/event/ad_error_event.dart b/lib/event/ad_error_event.dart
deleted file mode 100644
index 9580b3b..0000000
--- a/lib/event/ad_error_event.dart
+++ /dev/null
@@ -1,24 +0,0 @@
-import 'ad_event.dart';
-
-/// 广告错误事件
-class AdErrorEvent extends AdEvent {
- AdErrorEvent(
- {required this.errCode,
- required this.errMsg,
- required String adId,
- required String action})
- : super(adId: adId, action: action);
- // 错误码
- final int errCode;
- // 错误信息
- final String errMsg;
- // 解析 json 为错误事件对象
- factory AdErrorEvent.fromJson(Map json) {
- return AdErrorEvent(
- errCode: json['errCode'],
- errMsg: json['errMsg'],
- adId: json['adId'],
- action: json['action'],
- );
- }
-}
diff --git a/lib/event/ad_event.dart b/lib/event/ad_event.dart
deleted file mode 100644
index 9927678..0000000
--- a/lib/event/ad_event.dart
+++ /dev/null
@@ -1,30 +0,0 @@
-import 'ad_error_event.dart';
-import 'ad_event_action.dart';
-import 'ad_reward_event.dart';
-export 'ad_error_event.dart';
-export 'ad_event_action.dart';
-export 'ad_reward_event.dart';
-
-/// 广告事件
-class AdEvent {
- AdEvent({required this.adId, required this.action});
- // 广告 id
- final String adId;
- // 操作
- final String action;
-
- /// 解析 AdEvent
- factory AdEvent.fromJson(Map json) {
- String action = json['action'];
- if (action == AdEventAction.onAdError) {
- return AdErrorEvent.fromJson(json);
- } else if (action == AdEventAction.onAdReward) {
- return AdRewardEvent.fromJson(json);
- } else {
- return AdEvent(
- adId: json['adId'],
- action: action,
- );
- }
- }
-}
diff --git a/lib/event/ad_event_action.dart b/lib/event/ad_event_action.dart
deleted file mode 100644
index 3723d5d..0000000
--- a/lib/event/ad_event_action.dart
+++ /dev/null
@@ -1,21 +0,0 @@
-/// 广告事件操作
-class AdEventAction {
- // 广告错误
- static final String onAdError = "onAdError";
- // 广告加载成功
- static final String onAdLoaded = "onAdLoaded";
- // 广告填充
- static final String onAdPresent = "onAdPresent";
- // 广告曝光
- static final String onAdExposure = "onAdExposure";
- // 广告关闭(开屏计时结束或者用户点击关闭)
- static final String onAdClosed = "onAdClosed";
- // 广告点击
- static final String onAdClicked = "onAdClicked";
- // 广告跳过
- static final String onAdSkip = "onAdSkip";
- // 广告播放或计时完毕
- static final String onAdComplete = "onAdComplete";
- // 获得广告激励
- static final String onAdReward = "onAdReward";
-}
diff --git a/lib/event/ad_event_handler.dart b/lib/event/ad_event_handler.dart
deleted file mode 100644
index a7f7921..0000000
--- a/lib/event/ad_event_handler.dart
+++ /dev/null
@@ -1,13 +0,0 @@
-import 'ad_event.dart';
-export 'ad_event.dart';
-
-/// 广告事件回调监听
-typedef OnAdEventListener = void Function(AdEvent event);
-
-/// 处理广告事件
-void hanleAdEvent(dynamic data, OnAdEventListener listener) {
- if (data != null) {
- AdEvent adEvent = AdEvent.fromJson(data);
- listener.call(adEvent);
- }
-}
diff --git a/lib/event/ad_reward_event.dart b/lib/event/ad_reward_event.dart
deleted file mode 100644
index 27bc846..0000000
--- a/lib/event/ad_reward_event.dart
+++ /dev/null
@@ -1,28 +0,0 @@
-import 'ad_event.dart';
-
-/// 广告激励事件
-class AdRewardEvent extends AdEvent {
- AdRewardEvent(
- {required this.transId,
- this.customData,
- this.userId,
- required String adId,
- required String action})
- : super(adId: adId, action: action);
- // 激励服务端验证的唯一 ID
- final String transId;
- // 服务端验证的自定义信息
- final String? customData;
- // 服务端验证的用户信息
- final String? userId;
- // 解析 json 为激励事件对象
- factory AdRewardEvent.fromJson(Map json) {
- return AdRewardEvent(
- adId: json['adId'],
- action: json['action'],
- transId: json['transId'],
- customData: json['customData'],
- userId: json['userId'],
- );
- }
-}
diff --git a/lib/express/express_ad_view.dart b/lib/express/express_ad_view.dart
new file mode 100644
index 0000000..089b430
--- /dev/null
+++ b/lib/express/express_ad_view.dart
@@ -0,0 +1,150 @@
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:union_ad_ssgf/flutter_union_ad.dart';
+
+class ExpressAdView extends StatefulWidget {
+ final String androidId;
+ final String iosId;
+ final int viewWidth;
+ final int viewHeight;
+ final FlutterUnionAdExpressCallBack? callBack;
+ final bool downloadConfirm;
+ final bool isBidding;
+ final FlutterUnioAdBiddingController? bidding;
+
+ const ExpressAdView({
+ Key? key,
+ required this.androidId,
+ required this.iosId,
+ required this.viewWidth,
+ required this.viewHeight,
+ this.callBack,
+ required this.downloadConfirm,
+ required this.isBidding,
+ this.bidding,
+ }) : super(key: key);
+
+ @override
+ State createState() => _ExpressAdViewState();
+}
+
+class _ExpressAdViewState extends State {
+ final String _viewType = "com.example.union_ad_ssgf/NativeExpressAdView";
+
+ MethodChannel? _channel;
+
+ //广告是否显示
+ bool _isShowAd = true;
+
+ double _width = 0;
+ double _height = 0;
+
+ @override
+ void initState() {
+ super.initState();
+ _width = widget.viewWidth.toDouble();
+ _height = widget.viewHeight.toDouble();
+ setState(() {});
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ if (!_isShowAd) {
+ return Container();
+ }
+ if (defaultTargetPlatform == TargetPlatform.android) {
+ return SizedBox(
+ width: _width,
+ height: _height,
+ child: AndroidView(
+ viewType: _viewType,
+ creationParams: {
+ "androidId": widget.androidId,
+ "viewWidth": widget.viewWidth,
+ "viewHeight": widget.viewHeight,
+ "downloadConfirm": widget.downloadConfirm,
+ "isBidding": widget.isBidding,
+ },
+ onPlatformViewCreated: _registerChannel,
+ creationParamsCodec: const StandardMessageCodec(),
+ ),
+ );
+ } else if (defaultTargetPlatform == TargetPlatform.iOS) {
+ return SizedBox(
+ width: _width,
+ height: _height,
+ child: UiKitView(
+ viewType: _viewType,
+ creationParams: {
+ "iosId": widget.iosId,
+ "viewWidth": widget.viewWidth,
+ "viewHeight": widget.viewHeight,
+ "isBidding": widget.isBidding,
+ },
+ onPlatformViewCreated: _registerChannel,
+ creationParamsCodec: const StandardMessageCodec(),
+ ),
+ );
+ } else {
+ return Container();
+ }
+ }
+
+ //注册cannel
+ void _registerChannel(int id) {
+ _channel = MethodChannel("${_viewType}_$id");
+ _channel?.setMethodCallHandler(_platformCallHandler);
+ widget.bidding?.init(_channel);
+ }
+
+ //监听原生view传值
+ Future _platformCallHandler(MethodCall call) async {
+ switch (call.method) {
+ //显示广告
+ case FlutterTencentadMethod.onShow:
+ Map map = call.arguments;
+ if (mounted) {
+ setState(() {
+ _width = map["width"];
+ _height = map["height"];
+ _isShowAd = true;
+ });
+ }
+ widget.callBack?.onShow!();
+ break;
+ //广告加载失败
+ case FlutterTencentadMethod.onFail:
+ if (mounted) {
+ setState(() {
+ _isShowAd = false;
+ });
+ }
+ Map map = call.arguments;
+ widget.callBack?.onFail!(map["code"], map["message"]);
+ break;
+ //点击
+ case FlutterTencentadMethod.onClick:
+ widget.callBack?.onClick!();
+ break;
+ //曝光
+ case FlutterTencentadMethod.onExpose:
+ widget.callBack?.onExpose!();
+ break;
+ //关闭
+ case FlutterTencentadMethod.onClose:
+ if (mounted) {
+ setState(() {
+ _isShowAd = false;
+ });
+ }
+ widget.callBack?.onClose!();
+ break;
+ //竞价
+ case FlutterTencentadMethod.onECPM:
+ Map map = call.arguments;
+ widget.callBack?.onECPM!(map["ecpmLevel"], map["ecpm"]);
+ break;
+ }
+ }
+}
diff --git a/lib/flutter_unio_ad_bidding_controller.dart b/lib/flutter_unio_ad_bidding_controller.dart
new file mode 100644
index 0000000..f987006
--- /dev/null
+++ b/lib/flutter_unio_ad_bidding_controller.dart
@@ -0,0 +1,87 @@
+part of 'flutter_union_ad.dart';
+
+/// @Description: 优量汇竞价
+class FlutterUnioAdBiddingController {
+ late MethodChannel? _methodChannel;
+
+ init(MethodChannel? method) {
+ _methodChannel = method;
+ }
+
+ //回传竞价结果
+ void biddingResult(FlutterTencentBiddingResult result) {
+ //竞价成功
+ if (result.isSuccess) {
+ _methodChannel?.invokeMethod('biddingSucceeded', {
+ 'expectCostPrice': result.expectCostPrice,
+ 'highestLossPrice': result.highestLossPrice,
+ });
+ //竞价失败
+ } else {
+ _methodChannel?.invokeMethod('biddingSucceeded', {
+ 'winPrice': result.winPrice,
+ 'lossReason': result.lossReason,
+ 'adnId': result.adnId,
+ });
+ }
+ }
+}
+
+class FlutterTencentBiddingResult {
+ int? expectCostPrice;
+ int? highestLossPrice;
+ int? winPrice;
+ int? lossReason;
+ String? adnId;
+
+ bool isSuccess = true;
+
+ FlutterTencentBiddingResult();
+
+ ///竞价成功
+ ///
+ ///[expectCostPrice] 竞胜出价,类型为Integer
+ ///
+ ///[highestLossPrice] 最大竞败方出价,类型为Integer
+ FlutterTencentBiddingResult success(
+ int expectCostPrice, int highestLossPrice) {
+ this.isSuccess = true;
+ this.expectCostPrice = expectCostPrice;
+ this.highestLossPrice = highestLossPrice;
+ return this;
+ }
+
+ ///竞价失败
+ ///
+ /// [winPrice] 本次竞胜方出价(单位:分),类型为Integer。选填
+ ///
+ /// [lossReason] 优量汇广告竞败原因,类型为Integer。必填 [FlutterTencentAdBiddingLossReason]
+ ///
+ /// [adnId] 本次竞胜方渠道ID,类型为Integer。必填。 [FlutterTencentAdADNID]
+ FlutterTencentBiddingResult fail(int winPrice, int lossReason, String adnId) {
+ this.isSuccess = false;
+ this.winPrice = winPrice;
+ this.lossReason = lossReason;
+ this.adnId = adnId;
+ return this;
+ }
+
+ FlutterTencentBiddingResult.fromJson(Map json) {
+ expectCostPrice = json['expectCostPrice'];
+ highestLossPrice = json['highestLossPrice'];
+ winPrice = json['winPrice'];
+ lossReason = json['lossReason'];
+ adnId = json['adnId'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['isSuccess'] = this.isSuccess;
+ data['expectCostPrice'] = this.expectCostPrice;
+ data['highestLossPrice'] = this.highestLossPrice;
+ data['winPrice'] = this.winPrice;
+ data['lossReason'] = this.lossReason;
+ data['adnId'] = this.adnId;
+ return data;
+ }
+}
diff --git a/lib/flutter_union_ad.dart b/lib/flutter_union_ad.dart
new file mode 100644
index 0000000..17c7103
--- /dev/null
+++ b/lib/flutter_union_ad.dart
@@ -0,0 +1,275 @@
+export 'flutter_union_ad_stream.dart';
+export 'flutter_union_ad_code.dart.dart';
+
+import 'dart:async';
+
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:union_ad_ssgf/banner/banner_ad_view.dart';
+import 'package:union_ad_ssgf/splash/splash_ad_view.dart';
+import 'flutter_union_ad_code.dart.dart';
+
+import 'express/express_ad_view.dart';
+
+part 'flutter_union_ad_callback.dart';
+
+part 'flutter_unio_ad_bidding_controller.dart';
+
+class FlutterUnionAd {
+ static const MethodChannel _channel = MethodChannel('flutter_union_ad');
+
+ ///
+ /// # SDK注册初始化
+ ///
+ /// [androidId] androidId 必填
+ ///
+ /// [iosId] iosId 必填
+ ///
+ /// [channelId] channelId 渠道id [FlutterTencentadChannel]
+ ///
+ /// [personalized] personalized 是否开启个性化广告 [FlutterTencentadPersonalized]
+ ///
+ static Future register({
+ required String androidId,
+ required String iosId,
+ int? personalized,
+ bool? debug,
+ int? channelId,
+ }) async {
+ return await _channel.invokeMethod("register", {
+ "androidId": androidId,
+ "iosId": iosId,
+ "debug": debug ?? false,
+ "channelId": channelId ?? FlutterTencentadChannel.other,
+ "personalized": personalized ?? FlutterTencentadPersonalized.show,
+ });
+ }
+
+ ///
+ /// # 获取SDK版本号
+ ///
+ static Future getSDKVersion() async {
+ return await _channel.invokeMethod("getSDKVersion");
+ }
+
+ ///
+ /// # 激励视频广告预加载
+ ///
+ /// [androidId] android广告ID
+ ///
+ /// [iosId] ios广告ID
+ ///
+ /// [rewardName] 奖励名称
+ ///
+ /// [rewardAmount] 奖励金额
+ ///
+ /// [userID] 用户id
+ ///
+ /// [customData] 扩展参数,服务器回调使用
+ ///
+ /// [downloadConfirm] 下载二次确认弹窗 默认false
+ ///
+ /// [videoMuted] 是否静音 默认false
+ ///
+ /// [isBidding] 是否开启竞价模式 默认false
+ static Future loadRewardVideoAd({
+ required String androidId,
+ required String iosId,
+ required String rewardName,
+ required int rewardAmount,
+ required String userID,
+ String? customData,
+ bool? downloadConfirm,
+ bool? videoMuted,
+ bool? isBidding,
+ }) async {
+ return await _channel.invokeMethod("loadRewardVideoAd", {
+ "androidId": androidId,
+ "iosId": iosId,
+ "rewardName": rewardName,
+ "rewardAmount": rewardAmount,
+ "userID": userID,
+ "customData": customData ?? "",
+ "videoMuted": videoMuted ?? false,
+ "downloadConfirm": downloadConfirm ?? false,
+ "isBidding": isBidding ?? false,
+ });
+ }
+
+ ///
+ /// # 显示激励广告
+ ///
+ /// [result] 竞价成功、失败后调用 [FlutterTencentBiddingResult] ,isBidding = true时必传
+ static Future showRewardVideoAd(
+ {FlutterTencentBiddingResult? result}) async {
+ return await _channel.invokeMethod(
+ "showRewardVideoAd", result?.toJson() ?? {});
+ }
+
+ ///
+ /// # 预加载插屏广告
+ ///
+ /// [androidId] android广告ID
+ ///
+ /// [iosId] ios广告ID
+ ///
+ /// [isFullScreen] 是否全屏
+ ///
+ /// [downloadConfirm] 下载二次确认弹窗 默认false
+ ///
+ /// [isBidding] 是否开启竞价模式 默认false
+ ///
+ static Future loadUnifiedInterstitialAD({
+ required String androidId,
+ required String iosId,
+ required bool isFullScreen,
+ bool? downloadConfirm,
+ bool? isBidding,
+ }) async {
+ return await _channel.invokeMethod("loadInterstitialAD", {
+ "androidId": androidId,
+ "iosId": iosId,
+ "isFullScreen": isFullScreen,
+ "downloadConfirm": downloadConfirm ?? false,
+ "isBidding": isBidding ?? false,
+ });
+ }
+
+ ///
+ /// # 显示新模板渲染插屏
+ ///
+ ///
+ /// [result] 竞价成功、失败后调用 [FlutterTencentBiddingResult] ,isBidding = true时必传
+ ///
+ static Future showUnifiedInterstitialAD(
+ {FlutterTencentBiddingResult? result}) async {
+ return await _channel.invokeMethod(
+ "showInterstitialAD", result?.toJson() ?? {});
+ }
+
+ ///
+ /// # banner广告
+ ///
+ /// [androidId] android广告ID
+ ///
+ /// [iosId] ios广告ID
+ ///
+ /// [viewWidth] 广告宽 单位dp
+ ///
+ /// [viewHeight] 广告高 单位dp 宽高比应该为6.4:1
+ ///
+ /// [FlutterTencentAdBannerCallBack] 广告回调
+ ///
+ /// [downloadConfirm] 下载二次确认弹窗 默认false
+ ///
+ /// [isBidding] 是否开启竞价模式 默认false
+ ///
+ /// [bidding] 竞价成功、失败后调用 [FlutterTencentAdBiddingController] ,isBidding = true时必传
+ ///
+ static Widget bannerAdView({
+ required String androidId,
+ required String iosId,
+ required double viewWidth,
+ required double viewHeight,
+ bool? downloadConfirm,
+ bool? isBidding,
+ FlutterUnioAdBiddingController? bidding,
+ FlutterUnionAdBannerCallBack? callBack,
+ }) {
+ return BannerAdView(
+ androidId: androidId,
+ iosId: iosId,
+ viewWidth: viewWidth,
+ viewHeight: viewHeight,
+ callBack: callBack,
+ downloadConfirm: downloadConfirm ?? false,
+ isBidding: isBidding ?? false,
+ bidding: bidding,
+ );
+ }
+
+ ///
+ /// # 开屏广告
+ ///
+ /// [androidId] android广告ID
+ ///
+ /// [iosId] ios广告ID
+ ///
+ /// [fetchDelay] 设置开屏广告从请求到展示所花的最大时长(并不是指广告曝光时长),
+ /// 取值范围为[1500, 5000]ms。如果需要使用默认值,可以调用上一个构造方法,
+ /// 或者给 fetchDelay 设为0。
+ ///
+ /// [FlutterTencentAdSplashCallBack] 广告回调
+ ///
+ /// [downloadConfirm] 下载二次确认弹窗 默认false
+ ///
+ /// [isBidding] 是否开启竞价模式 默认false
+ ///
+ /// [bidding] 竞价成功、失败后调用 [FlutterTencentAdBiddingController] ,isBidding = true时必传
+ ///
+ static Widget splashAdView({
+ required String androidId,
+ required String iosId,
+ required int fetchDelay,
+ bool? downloadConfirm,
+ bool? isBidding,
+ FlutterUnioAdBiddingController? bidding,
+ FlutterUnionAdSplashCallBack? callBack,
+ }) {
+ return SplashAdView(
+ androidId: androidId,
+ iosId: iosId,
+ fetchDelay: fetchDelay,
+ callBack: callBack,
+ downloadConfirm: downloadConfirm ?? false,
+ isBidding: isBidding ?? false,
+ bidding: bidding,
+ );
+ }
+
+ ///
+ /// # 动态信息流/横幅/视频贴片广告
+ ///
+ /// [androidId] android广告ID
+ ///
+ /// [iosId] ios广告ID
+ ///
+ /// [viewWidth] 广告宽 单位dp
+ ///
+ /// [viewHeight] 广告高 单位dp
+ ///
+ /// [FlutterTencentAdExpressCallBack] 回调事件
+ ///
+ /// [downloadConfirm] 下载二次确认弹窗 默认false
+ ///
+ /// [isBidding] 是否开启竞价模式 默认false
+ ///
+ /// [bidding] 竞价成功、失败后调用 [FlutterTencentAdBiddingController] ,isBidding = true时必传
+ ///
+ static Widget expressAdView({
+ required String androidId,
+ required String iosId,
+ required int viewWidth,
+ required int viewHeight,
+ bool? downloadConfirm,
+ bool? isBidding,
+ FlutterUnioAdBiddingController? bidding,
+ FlutterUnionAdExpressCallBack? callBack,
+ }) {
+ return ExpressAdView(
+ androidId: androidId,
+ iosId: iosId,
+ viewWidth: viewWidth,
+ viewHeight: viewHeight,
+ callBack: callBack,
+ downloadConfirm: downloadConfirm ?? false,
+ isBidding: isBidding ?? false,
+ bidding: bidding,
+ );
+ }
+
+ ///进入APP下载列表页
+ static Future enterAPPDownloadListPage() async {
+ return await _channel.invokeMethod("enterAPPDownloadListPage", {});
+ }
+}
diff --git a/lib/flutter_union_ad_callback.dart b/lib/flutter_union_ad_callback.dart
new file mode 100644
index 0000000..ee21c7e
--- /dev/null
+++ b/lib/flutter_union_ad_callback.dart
@@ -0,0 +1,158 @@
+part of 'flutter_union_ad.dart';
+
+/// @Description: dart类作用描述
+
+///显示
+typedef TOnShow = void Function();
+
+///曝光
+typedef TOnExpose = void Function();
+
+///失败
+typedef TOnFail = void Function(int code, dynamic message);
+
+///点击
+typedef TOnClick = void Function();
+
+///视频播放
+typedef TOnVideoPlay = void Function();
+
+///视频暂停
+typedef TOnVideoPause = void Function();
+
+///视频播放结束
+typedef TOnVideoStop = void Function();
+
+///跳过
+typedef TOnSkip = void Function();
+
+///倒计时结束
+typedef TOnFinish = void Function();
+
+///加载超时
+typedef TOnTimeOut = void Function();
+
+///关闭
+typedef TOnClose = void Function();
+
+///广告预加载完成
+typedef TOnReady = void Function();
+
+///广告预加载未完成
+typedef TOnUnReady = void Function();
+
+///广告奖励验证
+typedef TOnVerify = void Function(
+ String transId, String rewardName, int rewardAmount);
+
+///倒计时
+typedef TOnADTick = void Function(int time);
+
+///竞价回调
+typedef TOnECPM = void Function(String ecpmLevel, int ecpm);
+
+///banner广告回调
+class FlutterUnionAdBannerCallBack {
+ TOnShow? onShow;
+ TOnFail? onFail;
+ TOnClick? onClick;
+ TOnExpose? onExpose;
+ TOnClose? onClose;
+ TOnECPM? onECPM;
+
+ FlutterUnionAdBannerCallBack(
+ {this.onShow,
+ this.onFail,
+ this.onClick,
+ this.onExpose,
+ this.onClose,
+ this.onECPM});
+}
+
+///动态信息流/横幅/视频贴片广告回调
+class FlutterUnionAdExpressCallBack {
+ TOnShow? onShow;
+ TOnFail? onFail;
+ TOnClick? onClick;
+ TOnExpose? onExpose;
+ TOnClose? onClose;
+ TOnECPM? onECPM;
+
+ FlutterUnionAdExpressCallBack(
+ {this.onShow,
+ this.onFail,
+ this.onClick,
+ this.onExpose,
+ this.onClose,
+ this.onECPM});
+}
+
+///开屏广告回调
+class FlutterUnionAdSplashCallBack {
+ TOnClose? onClose;
+ TOnShow? onShow;
+ TOnFail? onFail;
+ TOnClick? onClick;
+ TOnExpose? onExpose;
+ TOnADTick? onADTick;
+ TOnECPM? onECPM;
+
+ FlutterUnionAdSplashCallBack(
+ {this.onShow,
+ this.onFail,
+ this.onClick,
+ this.onClose,
+ this.onExpose,
+ this.onADTick,
+ this.onECPM});
+}
+
+///插屏广告回调
+class FlutterUnionAdInteractionCallBack {
+ TOnShow? onShow;
+ TOnClick? onClick;
+ TOnClose? onClose;
+ TOnFail? onFail;
+ TOnReady? onReady;
+ TOnUnReady? onUnReady;
+ TOnExpose? onExpose;
+ TOnVerify? onVerify;
+ TOnECPM? onECPM;
+
+ FlutterUnionAdInteractionCallBack(
+ {this.onShow,
+ this.onClick,
+ this.onClose,
+ this.onFail,
+ this.onExpose,
+ this.onReady,
+ this.onUnReady,
+ this.onVerify,
+ this.onECPM});
+}
+
+///激励广告回调
+class FlutterUnionAdRewardCallBack {
+ TOnShow? onShow;
+ TOnClose? onClose;
+ TOnExpose? onExpose;
+ TOnFail? onFail;
+ TOnClick? onClick;
+ TOnVerify? onVerify;
+ TOnReady? onReady;
+ TOnFinish? onFinish;
+ TOnUnReady? onUnReady;
+ TOnECPM? onECPM;
+
+ FlutterUnionAdRewardCallBack(
+ {this.onShow,
+ this.onClick,
+ this.onExpose,
+ this.onClose,
+ this.onFail,
+ this.onVerify,
+ this.onReady,
+ this.onFinish,
+ this.onUnReady,
+ this.onECPM});
+}
diff --git a/lib/flutter_union_ad_code.dart.dart b/lib/flutter_union_ad_code.dart.dart
new file mode 100644
index 0000000..23f63c9
--- /dev/null
+++ b/lib/flutter_union_ad_code.dart.dart
@@ -0,0 +1,142 @@
+///数据类型
+class FlutterUnionAdCode {
+ static const String adType = "adType";
+
+ ///激励广告
+ static const String rewardAd = "rewardAd";
+
+ ///插屏广告
+ static const String interactAd = "interactAd";
+}
+
+class FlutterTencentadMethod {
+ ///stream中 广告方法
+ static const String onAdMethod = "onAdMethod";
+
+ ///广告加载状态 view使用
+ ///显示view
+ static const String onShow = "onShow";
+
+ ///广告曝光
+ static const String onExpose = "onExpose";
+
+ ///加载失败
+ static const String onFail = "onFail";
+
+ ///点击
+ static const String onClick = "onClick";
+
+ ///视频播放
+ static const String onVideoPlay = "onVideoPlay";
+
+ ///视频暂停
+ static const String onVideoPause = "onVideoPause";
+
+ ///视频结束
+ static const String onVideoStop = "onVideoStop";
+
+ ///倒计时结束
+ static const String onFinish = "onFinish";
+
+ ///加载超时
+ static const String onTimeOut = "onTimeOut";
+
+ ///广告关闭
+ static const String onClose = "onClose";
+
+ ///广告奖励校验
+ static const String onVerify = "onVerify";
+
+ ///广告预加载完成
+ static const String onReady = "onReady";
+
+ ///广告未预加载
+ static const String onUnReady = "onUnReady";
+
+ ///倒计时
+ static const String onADTick = "onADTick";
+
+ ///竞价
+ static const String onECPM = "onECPM";
+}
+
+///渠道id
+class FlutterTencentadChannel {
+ ///百度
+ static const int baidu = 1;
+
+ ///头条
+ static const int toutiao = 2;
+
+ ///优量汇
+ static const int tencent = 3;
+
+ ///搜狗
+ static const int sougou = 4;
+
+ ///其他网盟
+ static const int otherAd = 5;
+
+ ///oppe
+ static const int oppo = 6;
+
+ ///vivo
+ static const int vivo = 7;
+
+ ///huawei
+ static const int huawei = 8;
+
+ ///应用宝
+ static const int yinyongbao = 9;
+
+ ///小米
+ static const int xiaomi = 10;
+
+ ///金立
+ static const int jinli = 11;
+
+ ///百度手机助手
+ static const int baiduMobile = 12;
+
+ ///魅族
+ static const int meizu = 13;
+
+ ///App Store
+ static const int appStore = 14;
+
+ ///其他
+ static const int other = 999;
+}
+
+///个性化广告
+class FlutterTencentadPersonalized {
+ ///屏蔽个性化推荐广告
+ static const int close = 1;
+
+ ///不屏蔽个性化推荐广告
+ static const int show = 0;
+}
+
+///竞价失败原因
+class FlutterTencentAdBiddingLossReason {
+ /// 竞争力不足,如优量汇不是本次竞价的最高出价方,可上报此竞败原因
+ static const int LOW_PRICE = 1;
+
+ /// 返回超时,如优量汇在本次竞价中未返回广告,可上报此竞败原因
+ static const int TIME_OUT = 2;
+
+ ///其他
+ static const int OTHER = 10001;
+}
+
+///本次竞胜方渠道ID
+class FlutterTencentAdADNID {
+ ///1 - 输给优量汇其它广告,当优量汇目标价报价为本次竞价的最高报价时,可上报此值,仅对混合比价类型的开发者适用
+ static const String tencentADN = "1";
+
+ /// 2 - 输给第三方ADN,当其它ADN报价为本次竞价的最高报价时,可上报此值,您无需回传具体竞胜方渠道;
+ static const String othoerADN = "2";
+
+ /// 3 - 输给自售广告主,当自售广告源报价为本次竞价的最高报价时,可上报此值,仅对有自售广告源的开发者使用
+ static const String appADN = "3";
+}
diff --git a/lib/flutter_union_ad_stream.dart b/lib/flutter_union_ad_stream.dart
new file mode 100644
index 0000000..907c082
--- /dev/null
+++ b/lib/flutter_union_ad_stream.dart
@@ -0,0 +1,143 @@
+import 'dart:async';
+
+import 'package:flutter/services.dart';
+
+import 'flutter_union_ad.dart';
+
+/// @Description: dart类作用描述
+const EventChannel tencentAdEventEvent =
+ EventChannel("com.example.union_ad_ssgf/adevent");
+
+class FlutterUnionAdStream {
+ ///
+ /// # 注册stream监听原生返回的信息
+ /// [rewardAdCallBack] 激励广告回调
+ /// [interactionAdCallBack] 插屏广告回调
+ ///
+ static StreamSubscription initAdStream(
+ {FlutterUnionAdRewardCallBack? flutterTencentadRewardCallBack,
+ FlutterUnionAdInteractionCallBack? flutterTencentadInteractionCallBack}) {
+ StreamSubscription _adStream =
+ tencentAdEventEvent.receiveBroadcastStream().listen((data) {
+ switch (data[FlutterUnionAdCode.adType]) {
+ ///激励广告
+ case FlutterUnionAdCode.rewardAd:
+ switch (data[FlutterTencentadMethod.onAdMethod]) {
+ case FlutterTencentadMethod.onShow:
+ if (flutterTencentadRewardCallBack?.onShow != null) {
+ flutterTencentadRewardCallBack?.onShow!();
+ }
+ break;
+ case FlutterTencentadMethod.onClose:
+ if (flutterTencentadRewardCallBack?.onClose != null) {
+ flutterTencentadRewardCallBack?.onClose!();
+ }
+ break;
+ case FlutterTencentadMethod.onFail:
+ if (flutterTencentadRewardCallBack?.onFail != null) {
+ flutterTencentadRewardCallBack?.onFail!(
+ data["code"], data["message"]);
+ }
+ break;
+ case FlutterTencentadMethod.onClick:
+ if (flutterTencentadRewardCallBack?.onClick != null) {
+ flutterTencentadRewardCallBack?.onClick!();
+ }
+ break;
+ case FlutterTencentadMethod.onVerify:
+ if (flutterTencentadRewardCallBack?.onVerify != null) {
+ flutterTencentadRewardCallBack?.onVerify!(
+ data["transId"], data["rewardName"], data["rewardAmount"]);
+ }
+ break;
+ case FlutterTencentadMethod.onFinish:
+ if (flutterTencentadRewardCallBack?.onFinish != null) {
+ flutterTencentadRewardCallBack?.onFinish!();
+ }
+ break;
+ case FlutterTencentadMethod.onReady:
+ if (flutterTencentadRewardCallBack?.onReady != null) {
+ flutterTencentadRewardCallBack?.onReady!();
+ }
+ break;
+ case FlutterTencentadMethod.onUnReady:
+ if (flutterTencentadRewardCallBack?.onUnReady != null) {
+ flutterTencentadRewardCallBack?.onUnReady!();
+ }
+ break;
+ case FlutterTencentadMethod.onExpose:
+ if (flutterTencentadRewardCallBack?.onExpose != null) {
+ flutterTencentadRewardCallBack?.onExpose!();
+ }
+ break;
+ case FlutterTencentadMethod.onECPM:
+ if (flutterTencentadRewardCallBack?.onECPM != null) {
+ flutterTencentadRewardCallBack?.onECPM!(
+ data["ecpmLevel"], data["ecpm"]);
+ }
+ break;
+ }
+ break;
+
+ ///插屏广告
+ case FlutterUnionAdCode.interactAd:
+ switch (data[FlutterTencentadMethod.onAdMethod]) {
+ case FlutterTencentadMethod.onShow:
+ if (flutterTencentadInteractionCallBack?.onShow != null) {
+ flutterTencentadInteractionCallBack?.onShow!();
+ }
+ break;
+ case FlutterTencentadMethod.onClose:
+ if (flutterTencentadInteractionCallBack?.onClose != null) {
+ flutterTencentadInteractionCallBack?.onClose!();
+ }
+ break;
+ case FlutterTencentadMethod.onFail:
+ if (flutterTencentadInteractionCallBack?.onFail != null) {
+ flutterTencentadInteractionCallBack?.onFail!(
+ data["code"], data["message"]);
+ }
+ break;
+ case FlutterTencentadMethod.onClick:
+ if (flutterTencentadInteractionCallBack?.onClick != null) {
+ flutterTencentadInteractionCallBack?.onClick!();
+ }
+ break;
+ case FlutterTencentadMethod.onExpose:
+ if (flutterTencentadInteractionCallBack?.onExpose != null) {
+ flutterTencentadInteractionCallBack?.onExpose!();
+ }
+ break;
+ case FlutterTencentadMethod.onReady:
+ if (flutterTencentadInteractionCallBack?.onReady != null) {
+ flutterTencentadInteractionCallBack?.onReady!();
+ }
+ break;
+ case FlutterTencentadMethod.onUnReady:
+ if (flutterTencentadInteractionCallBack?.onUnReady != null) {
+ flutterTencentadInteractionCallBack?.onUnReady!();
+ }
+ break;
+ case FlutterTencentadMethod.onVerify:
+ if (flutterTencentadInteractionCallBack?.onVerify != null) {
+ flutterTencentadInteractionCallBack?.onVerify!(
+ data["transId"], "", 0);
+ }
+ break;
+ case FlutterTencentadMethod.onECPM:
+ if (flutterTencentadInteractionCallBack?.onECPM != null) {
+ flutterTencentadInteractionCallBack?.onECPM!(
+ data["ecpmLevel"], data["ecpm"]);
+ }
+ break;
+ }
+ break;
+ }
+ });
+ return _adStream;
+ }
+
+ static void deleteAdStream(StreamSubscription stream) {
+ stream.cancel();
+ }
+}
diff --git a/lib/splash/splash_ad_view.dart b/lib/splash/splash_ad_view.dart
new file mode 100644
index 0000000..83437cf
--- /dev/null
+++ b/lib/splash/splash_ad_view.dart
@@ -0,0 +1,137 @@
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:union_ad_ssgf/flutter_union_ad.dart';
+
+class SplashAdView extends StatefulWidget {
+ final String androidId;
+ final String iosId;
+ final int fetchDelay;
+ final FlutterUnionAdSplashCallBack? callBack;
+ final bool downloadConfirm;
+ final bool isBidding;
+ final FlutterUnioAdBiddingController? bidding;
+
+ const SplashAdView({
+ Key? key,
+ required this.androidId,
+ required this.iosId,
+ required this.fetchDelay,
+ this.callBack,
+ required this.downloadConfirm,
+ required this.isBidding,
+ this.bidding,
+ }) : super(key: key);
+
+ @override
+ State createState() => _SplashAdViewState();
+}
+
+class _SplashAdViewState extends State {
+ final String _viewType = "com.example.union_ad_ssgf/SplashAdView";
+
+ MethodChannel? _channel;
+
+ //广告是否显示
+ bool _isShowAd = true;
+
+ @override
+ void initState() {
+ super.initState();
+ _isShowAd = true;
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ if (!_isShowAd) {
+ return Container();
+ }
+ if (defaultTargetPlatform == TargetPlatform.android) {
+ return SizedBox(
+ width: MediaQuery.of(context).size.width,
+ height: MediaQuery.of(context).size.height,
+ child: AndroidView(
+ viewType: _viewType,
+ creationParams: {
+ "androidId": widget.androidId,
+ "fetchDelay": widget.fetchDelay,
+ "downloadConfirm": widget.downloadConfirm,
+ "isBidding": widget.isBidding,
+ },
+ onPlatformViewCreated: _registerChannel,
+ creationParamsCodec: const StandardMessageCodec(),
+ ),
+ );
+ } else if (defaultTargetPlatform == TargetPlatform.iOS) {
+ return SizedBox(
+ width: MediaQuery.of(context).size.width,
+ height: MediaQuery.of(context).size.height,
+ child: UiKitView(
+ viewType: _viewType,
+ creationParams: {
+ "iosId": widget.iosId,
+ "fetchDelay": widget.fetchDelay,
+ "isBidding": widget.isBidding,
+ },
+ onPlatformViewCreated: _registerChannel,
+ creationParamsCodec: const StandardMessageCodec(),
+ ),
+ );
+ } else {
+ return Container();
+ }
+ }
+
+ //注册cannel
+ void _registerChannel(int id) {
+ _channel = MethodChannel("${_viewType}_$id");
+ _channel?.setMethodCallHandler(_platformCallHandler);
+ widget.bidding?.init(_channel);
+ }
+
+ //监听原生view传值
+ Future _platformCallHandler(MethodCall call) async {
+ switch (call.method) {
+ //显示广告
+ case FlutterTencentadMethod.onShow:
+ widget.callBack?.onShow!();
+ if (mounted) {
+ setState(() {
+ _isShowAd = true;
+ });
+ }
+ break;
+ //关闭
+ case FlutterTencentadMethod.onClose:
+ widget.callBack?.onClose!();
+ break;
+ //广告加载失败
+ case FlutterTencentadMethod.onFail:
+ if (mounted) {
+ setState(() {
+ _isShowAd = false;
+ });
+ }
+ Map map = call.arguments;
+ widget.callBack?.onFail!(map["code"], map["message"]);
+ break;
+ //点击
+ case FlutterTencentadMethod.onClick:
+ widget.callBack?.onClick!();
+ break;
+ //曝光
+ case FlutterTencentadMethod.onExpose:
+ widget.callBack?.onExpose!();
+ break;
+ //倒计时
+ case FlutterTencentadMethod.onADTick:
+ widget.callBack?.onADTick!(call.arguments);
+ break;
+ //竞价
+ case FlutterTencentadMethod.onECPM:
+ Map map = call.arguments;
+ widget.callBack?.onECPM!(map["ecpmLevel"], map["ecpm"]);
+ break;
+ }
+ }
+}
diff --git a/lib/union_ad_ssgf.dart b/lib/union_ad_ssgf.dart
deleted file mode 100644
index 87cca0a..0000000
--- a/lib/union_ad_ssgf.dart
+++ /dev/null
@@ -1,99 +0,0 @@
-import 'dart:io';
-
-import 'package:flutter/services.dart';
-import 'package:union_ad_ssgf/event/ad_event_handler.dart';
-
-import 'union_ad_ssgf_platform_interface.dart';
-
-/// 三商共富 Flutter 广告插件
-class UnionAdSsgf {
- /// 方法通道
- static const MethodChannel _methodChannel =
- MethodChannel('union_ad_ssgf_method');
-
- /// 事件通道
- static const EventChannel _eventChannel = EventChannel('union_ad_ssgf_event');
-
- /// 请求应用跟踪透明度授权
- static Future get requestIDFA async {
- if (Platform.isIOS) {
- final bool result = await _methodChannel.invokeMethod('requestIDFA');
- return result;
- }
- return true;
- }
-
- /// 初始化广告
- /// [appId] 应用媒体ID
- static Future initAd(String appId) async {
- final bool result = await _methodChannel.invokeMethod(
- 'initAd',
- {'appId': appId},
- );
- print("🎉🎉🎉 UnionAd ==> 初始化完成");
- return result;
- }
-
- /// 设置个性化广告
- /// 0:代表开启个性化广告推荐,1:代表关闭个性化广告推荐
- static Future setPersonalizedState(int state) async {
- final bool result = await _methodChannel.invokeMethod(
- 'setPersonalizedState',
- {'state': state},
- );
- return result;
- }
-
- /// 展示开屏广告
- /// [posId] 广告位 id
- /// [logo] 如果传值则展示底部logo,不传不展示,则全屏展示
- /// [fetchDelay] 拉取广告的超时时间,默认值 3 秒,取值范围[1.5~5]秒
- static Future showSplashAd(String posId,
- {String? logo, double fetchDelay = 3}) async {
- final bool result = await _methodChannel.invokeMethod(
- 'showSplashAd',
- {
- 'posId': posId,
- 'logo': logo,
- 'fetchDelay': fetchDelay,
- },
- );
- return result;
- }
-
- /// 展示激励视频广告
- /// [posId] 广告位 id
- /// [playMuted] 是否静音播放
- /// [customData] 设置服务端验证的自定义信息
- /// [userId] 设置服务端验证的用户信息
- static Future showRewardVideoAd(
- String posId, {
- bool playMuted = false,
- String? customData,
- String? userId,
- }) async {
- final bool result = await _methodChannel.invokeMethod(
- 'showRewardVideoAd',
- {
- 'posId': posId,
- 'playMuted': playMuted,
- 'customData': customData,
- 'userId': userId,
- },
- );
- return result;
- }
-
- ///事件回调
- ///@params onData 事件回调
- static Future onEventListener(
- OnAdEventListener onAdEventListener) async {
- _eventChannel.receiveBroadcastStream().listen((data) {
- hanleAdEvent(data, onAdEventListener);
- });
- }
-
- Future getPlatformVersion() {
- return UnionAdSsgfPlatform.instance.getPlatformVersion();
- }
-}
diff --git a/lib/union_ad_ssgf_method_channel.dart b/lib/union_ad_ssgf_method_channel.dart
deleted file mode 100644
index 02bb843..0000000
--- a/lib/union_ad_ssgf_method_channel.dart
+++ /dev/null
@@ -1,17 +0,0 @@
-import 'package:flutter/foundation.dart';
-import 'package:flutter/services.dart';
-
-import 'union_ad_ssgf_platform_interface.dart';
-
-/// An implementation of [UnionAdSsgfPlatform] that uses method channels.
-class MethodChannelUnionAdSsgf extends UnionAdSsgfPlatform {
- /// The method channel used to interact with the native platform.
- @visibleForTesting
- final methodChannel = const MethodChannel('union_ad_ssgf_method');
-
- @override
- Future getPlatformVersion() async {
- final version = await methodChannel.invokeMethod('getPlatformVersion');
- return version;
- }
-}
diff --git a/lib/union_ad_ssgf_platform_interface.dart b/lib/union_ad_ssgf_platform_interface.dart
deleted file mode 100644
index 8fb70b8..0000000
--- a/lib/union_ad_ssgf_platform_interface.dart
+++ /dev/null
@@ -1,29 +0,0 @@
-import 'package:plugin_platform_interface/plugin_platform_interface.dart';
-
-import 'union_ad_ssgf_method_channel.dart';
-
-abstract class UnionAdSsgfPlatform extends PlatformInterface {
- /// Constructs a UnionAdSsgfPlatform.
- UnionAdSsgfPlatform() : super(token: _token);
-
- static final Object _token = Object();
-
- static UnionAdSsgfPlatform _instance = MethodChannelUnionAdSsgf();
-
- /// The default instance of [UnionAdSsgfPlatform] to use.
- ///
- /// Defaults to [MethodChannelUnionAdSsgf].
- static UnionAdSsgfPlatform get instance => _instance;
-
- /// Platform-specific implementations should set this with their own
- /// platform-specific class that extends [UnionAdSsgfPlatform] when
- /// they register themselves.
- static set instance(UnionAdSsgfPlatform instance) {
- PlatformInterface.verifyToken(instance, _token);
- _instance = instance;
- }
-
- Future getPlatformVersion() {
- throw UnimplementedError('platformVersion() has not been implemented.');
- }
-}
diff --git a/lib/union_ad_ssgf_web.dart b/lib/union_ad_ssgf_web.dart
deleted file mode 100644
index 4d935a7..0000000
--- a/lib/union_ad_ssgf_web.dart
+++ /dev/null
@@ -1,26 +0,0 @@
-// In order to *not* need this ignore, consider extracting the "web" version
-// of your plugin as a separate package, instead of inlining it in the same
-// package as the core of your plugin.
-// ignore: avoid_web_libraries_in_flutter
-
-import 'package:flutter_web_plugins/flutter_web_plugins.dart';
-import 'package:web/web.dart' as web;
-
-import 'union_ad_ssgf_platform_interface.dart';
-
-/// A web implementation of the UnionAdSsgfPlatform of the UnionAdSsgf plugin.
-class UnionAdSsgfWeb extends UnionAdSsgfPlatform {
- /// Constructs a UnionAdSsgfWeb
- UnionAdSsgfWeb();
-
- static void registerWith(Registrar registrar) {
- UnionAdSsgfPlatform.instance = UnionAdSsgfWeb();
- }
-
- /// Returns a [String] containing the version of the platform.
- @override
- Future getPlatformVersion() async {
- final version = web.window.navigator.userAgent;
- return version;
- }
-}
diff --git a/test/union_ad_ssgf_method_channel_test.dart b/test/union_ad_ssgf_method_channel_test.dart
deleted file mode 100644
index b11eb19..0000000
--- a/test/union_ad_ssgf_method_channel_test.dart
+++ /dev/null
@@ -1,27 +0,0 @@
-import 'package:flutter/services.dart';
-import 'package:flutter_test/flutter_test.dart';
-import 'package:union_ad_ssgf/union_ad_ssgf_method_channel.dart';
-
-void main() {
- TestWidgetsFlutterBinding.ensureInitialized();
-
- MethodChannelUnionAdSsgf platform = MethodChannelUnionAdSsgf();
- const MethodChannel channel = MethodChannel('union_ad_ssgf_method');
-
- setUp(() {
- TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(
- channel,
- (MethodCall methodCall) async {
- return '42';
- },
- );
- });
-
- tearDown(() {
- TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(channel, null);
- });
-
- test('getPlatformVersion', () async {
- expect(await platform.getPlatformVersion(), '42');
- });
-}
diff --git a/test/union_ad_ssgf_test.dart b/test/union_ad_ssgf_test.dart
index 0ab8320..021f830 100644
--- a/test/union_ad_ssgf_test.dart
+++ b/test/union_ad_ssgf_test.dart
@@ -1,29 +1,5 @@
-import 'package:flutter_test/flutter_test.dart';
-import 'package:union_ad_ssgf/union_ad_ssgf.dart';
-import 'package:union_ad_ssgf/union_ad_ssgf_platform_interface.dart';
-import 'package:union_ad_ssgf/union_ad_ssgf_method_channel.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
-class MockUnionAdSsgfPlatform
- with MockPlatformInterfaceMixin
- implements UnionAdSsgfPlatform {
+class MockUnionAdSsgfPlatform with MockPlatformInterfaceMixin {}
- @override
- Future getPlatformVersion() => Future.value('42');
-}
-
-void main() {
- final UnionAdSsgfPlatform initialPlatform = UnionAdSsgfPlatform.instance;
-
- test('$MethodChannelUnionAdSsgf is the default instance', () {
- expect(initialPlatform, isInstanceOf());
- });
-
- test('getPlatformVersion', () async {
- UnionAdSsgf unionAdSsgfPlugin = UnionAdSsgf();
- MockUnionAdSsgfPlatform fakePlatform = MockUnionAdSsgfPlatform();
- UnionAdSsgfPlatform.instance = fakePlatform;
-
- expect(await unionAdSsgfPlugin.getPlatformVersion(), '42');
- });
-}
+void main() {}