diff --git a/aes/build.gradle b/aes/build.gradle
index c9c1271c..2a780ce6 100644
--- a/aes/build.gradle
+++ b/aes/build.gradle
@@ -18,18 +18,22 @@ def genVersionName(def versionName){
}
android {
- compileSdkVersion 32
- buildToolsVersion "32.0.0"
+
+ // 1. compileSdkVersion:必须 ≥ targetSdkVersion,建议直接等于 targetSdkVersion(30)
+ compileSdkVersion 30
+
+ // 2. buildToolsVersion:需匹配 compileSdkVersion,建议使用 30.x.x 最新稳定版(无需高于 compileSdkVersion)
+ buildToolsVersion "30.0.3" // 这是 30 对应的最新稳定版,避免使用 beta 版
defaultConfig {
applicationId "cc.winboll.studio.aes"
- minSdkVersion 24
+ minSdkVersion 23
targetSdkVersion 30
versionCode 1
// versionName 更新后需要手动设置
// 项目模块目录的 build.gradle 文件的 stageCount=0
// Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
- versionName "15.10"
+ versionName "15.11"
if(true) {
versionName = genVersionName("${versionName}")
}
diff --git a/aes/build.properties b/aes/build.properties
index 14e2b616..d1d3269d 100644
--- a/aes/build.properties
+++ b/aes/build.properties
@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
-#Mon Sep 29 13:04:18 HKT 2025
+#Wed Nov 19 08:36:25 HKT 2025
stageCount=3
libraryProject=libaes
-baseVersion=15.10
-publishVersion=15.10.2
+baseVersion=15.11
+publishVersion=15.11.2
buildCount=0
-baseBetaVersion=15.10.3
+baseBetaVersion=15.11.3
diff --git a/aes/src/main/java/cc/winboll/studio/aes/App.java b/aes/src/main/java/cc/winboll/studio/aes/App.java
index 9b0fb3a9..9a6674ca 100644
--- a/aes/src/main/java/cc/winboll/studio/aes/App.java
+++ b/aes/src/main/java/cc/winboll/studio/aes/App.java
@@ -8,8 +8,7 @@ package cc.winboll.studio.aes;
import android.view.Gravity;
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
import cc.winboll.studio.libappbase.GlobalApplication;
-import com.hjq.toast.ToastUtils;
-import com.hjq.toast.style.WhiteToastStyle;
+import cc.winboll.studio.libappbase.ToastUtils;
public class App extends GlobalApplication {
@@ -19,15 +18,16 @@ public class App extends GlobalApplication {
@Override
public void onCreate() {
super.onCreate();
+ setIsDebugging(BuildConfig.DEBUG);
WinBoLLActivityManager.init(this);
// 初始化 Toast 框架
ToastUtils.init(this);
- // 设置 Toast 布局样式
- //ToastUtils.setView(R.layout.view_toast);
- ToastUtils.setStyle(new WhiteToastStyle());
- ToastUtils.setGravity(Gravity.BOTTOM, 0, 200);
-
}
+ @Override
+ public void onTerminate() {
+ super.onTerminate();
+ ToastUtils.release();
+ }
}
diff --git a/aes/src/main/java/cc/winboll/studio/aes/MainActivity.java b/aes/src/main/java/cc/winboll/studio/aes/MainActivity.java
index 40a70dbf..53968fd8 100644
--- a/aes/src/main/java/cc/winboll/studio/aes/MainActivity.java
+++ b/aes/src/main/java/cc/winboll/studio/aes/MainActivity.java
@@ -91,8 +91,8 @@ public class MainActivity extends DrawerFragmentActivity implements IWinBoLLActi
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar_library, menu);
- if(App.isDebuging()) {
- getMenuInflater().inflate(cc.winboll.studio.libapputils.R.menu.toolbar_studio_debug, menu);
+ if(App.isDebugging()) {
+ getMenuInflater().inflate(cc.winboll.studio.libaes.R.menu.toolbar_studio_debug, menu);
}
return super.onCreateOptionsMenu(menu);
}
diff --git a/build.gradle b/build.gradle
index 67994863..453f0841 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,6 +5,16 @@ buildscript {
// 设置本地Maven仓库路径
url 'file:///sdcard/.m2/repository/'
}
+
+ //米盟通过maven接入时,要做如下配置
+ maven {
+ url "https://repos.xiaomi.com/maven"
+ credentials {
+ username 'mimo-developer'
+ password 'AKCp8ih1PFG9tV8qaLyws67dLGZi8udFM39SfsHgihN15cgsiRvHuxj8JzFmuZjaViVeNawaA'
+ }
+ }
+
// Nexus Maven 库地址
// "WinBoLL Release"
maven { url "https://nexus.winboll.cc/repository/maven-public/" }
@@ -40,6 +50,15 @@ allprojects {
// 设置本地Maven仓库路径
url 'file:///sdcard/.m2/repository/'
}
+
+ //米盟通过maven接入时,要做如下配置
+ maven {
+ url "https://repos.xiaomi.com/maven"
+ credentials {
+ username 'mimo-developer'
+ password 'AKCp8ih1PFG9tV8qaLyws67dLGZi8udFM39SfsHgihN15cgsiRvHuxj8JzFmuZjaViVeNawaA'
+ }
+ }
// Nexus Maven 库地址
// "WinBoLL Release"
diff --git a/libaes/build.gradle b/libaes/build.gradle
index 88f73bdd..6fa4929a 100644
--- a/libaes/build.gradle
+++ b/libaes/build.gradle
@@ -4,11 +4,15 @@ apply from: '../.winboll/winboll_lib_build.gradle'
apply from: '../.winboll/winboll_lint_build.gradle'
android {
- compileSdkVersion 32
- buildToolsVersion "32.0.0"
+
+ // 1. compileSdkVersion:必须 ≥ targetSdkVersion,建议直接等于 targetSdkVersion(30)
+ compileSdkVersion 30
+
+ // 2. buildToolsVersion:需匹配 compileSdkVersion,建议使用 30.x.x 最新稳定版(无需高于 compileSdkVersion)
+ buildToolsVersion "30.0.3" // 这是 30 对应的最新稳定版,避免使用 beta 版
defaultConfig {
- minSdkVersion 24
+ minSdkVersion 23
targetSdkVersion 30
}
buildTypes {
@@ -20,13 +24,6 @@ android {
}
dependencies {
- api fileTree(dir: 'libs', include: ['*.jar'])
- api 'cc.winboll.studio:libapputils:15.10.2'
- api 'cc.winboll.studio:libappbase:15.10.9'
-
- // 吐司类库
- api 'com.github.getActivity:ToastUtils:10.5'
-
// 权限请求框架:https://github.com/getActivity/XXPermissions
api 'com.github.getActivity:XXPermissions:18.63'
// 下拉控件
@@ -52,4 +49,17 @@ dependencies {
//api 'androidx.vectordrawable:vectordrawable:1.1.0'
//api 'androidx.vectordrawable:vectordrawable-animated:1.1.0'
//api 'androidx.fragment:fragment:1.1.0'
+
+ // 米盟
+ implementation 'com.miui.zeus:mimo-ad-sdk:5.3.+'//请使用最新版sdk
+ //注意:以下5个库必须要引入
+ //implementation 'androidx.appcompat:appcompat:1.4.1'
+ implementation 'androidx.recyclerview:recyclerview:1.0.0'
+ implementation 'com.google.code.gson:gson:2.8.5'
+ implementation 'com.github.bumptech.glide:glide:4.9.0'
+ //annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
+
+ api 'cc.winboll.studio:libappbase:15.11.0'
+
+ api fileTree(dir: 'libs', include: ['*.jar'])
}
diff --git a/libaes/build.properties b/libaes/build.properties
index 256a9063..23ebe3f3 100644
--- a/libaes/build.properties
+++ b/libaes/build.properties
@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
-#Mon Sep 29 13:04:07 HKT 2025
+#Wed Nov 19 08:36:14 HKT 2025
stageCount=3
libraryProject=libaes
-baseVersion=15.10
-publishVersion=15.10.2
+baseVersion=15.11
+publishVersion=15.11.2
buildCount=0
-baseBetaVersion=15.10.3
+baseBetaVersion=15.11.3
diff --git a/libaes/src/main/AndroidManifest.xml b/libaes/src/main/AndroidManifest.xml
index 7c90badf..2f221dae 100644
--- a/libaes/src/main/AndroidManifest.xml
+++ b/libaes/src/main/AndroidManifest.xml
@@ -1,9 +1,25 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
+
diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java
index 812089e7..b6dfba12 100644
--- a/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java
+++ b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java
@@ -31,6 +31,9 @@ import cc.winboll.studio.libappbase.LogUtils;
import com.baoyz.widget.PullRefreshLayout;
import java.util.ArrayList;
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
+import cc.winboll.studio.libaes.views.ADsBannerView;
+import cc.winboll.studio.libappbase.LogActivity;
+import cc.winboll.studio.libappbase.ToastUtils;
public abstract class DrawerFragmentActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
@@ -71,17 +74,22 @@ public abstract class DrawerFragmentActivity extends AppCompatActivity implement
@Override
protected void onDestroy() {
super.onDestroy();
+ // 修复:释放广告资源,避免内存泄漏
+ ADsBannerView adsBannerView = findViewById(R.id.adsbanner);
+ if (adsBannerView != null) {
+ adsBannerView.releaseAdResources();
+ }
}
/*@Override
- public Intent getIntent() {
- // TODO: Implement this method
- return super.getIntent();
- }
+ public Intent getIntent() {
+ // TODO: Implement this method
+ return super.getIntent();
+ }
- public Context getContext() {
- return this.mContext;
- }*/
+ public Context getContext() {
+ return this.mContext;
+ }*/
@Override
public MenuInflater getMenuInflater() {
@@ -90,9 +98,9 @@ public abstract class DrawerFragmentActivity extends AppCompatActivity implement
}
/*public void setSubtitle(CharSequence context) {
- // TODO: Implement this method
- getSupportActionBar().setSubtitle(context);
- }*/
+ // TODO: Implement this method
+ getSupportActionBar().setSubtitle(context);
+ }*/
@Override
public void recreate() {
@@ -100,9 +108,9 @@ public abstract class DrawerFragmentActivity extends AppCompatActivity implement
}
/*@Override
- public boolean moveTaskToBack(boolean nonRoot) {
- return super.moveTaskToBack(nonRoot);
- }*/
+ public boolean moveTaskToBack(boolean nonRoot) {
+ return super.moveTaskToBack(nonRoot);
+ }*/
@Override
public void startActivity(Intent intent) {
@@ -115,24 +123,24 @@ public abstract class DrawerFragmentActivity extends AppCompatActivity implement
}
/*@Override
- public FragmentManager getSupportFragmentManager() {
- return super.getSupportFragmentManager();
- }
+ public FragmentManager getSupportFragmentManager() {
+ return super.getSupportFragmentManager();
+ }
- public void setSubtitle(int resId) {
- // TODO: Implement this method
- getSupportActionBar().setSubtitle(resId);
- }
+ public void setSubtitle(int resId) {
+ // TODO: Implement this method
+ getSupportActionBar().setSubtitle(resId);
+ }
- public void setTitle(CharSequence context) {
- // TODO: Implement this method
- getSupportActionBar().setTitle(context);
- }
+ public void setTitle(CharSequence context) {
+ // TODO: Implement this method
+ getSupportActionBar().setTitle(context);
+ }
- public void setTitle(int resId) {
- // TODO: Implement this method
- getSupportActionBar().setTitle(resId);
- }*/
+ public void setTitle(int resId) {
+ // TODO: Implement this method
+ getSupportActionBar().setTitle(resId);
+ }*/
@Override
public SharedPreferences getSharedPreferences(String name, int mode) {
@@ -175,6 +183,9 @@ public abstract class DrawerFragmentActivity extends AppCompatActivity implement
for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) {
getString(i);
}
+ } else if (R.id.item_log == item.getItemId()) {
+ ToastUtils.show("Test");
+ LogActivity.startLogActivity(this);
} else if (R.id.item_about == item.getItemId()) {
LogUtils.d(TAG, "onAbout");
} else if (android.R.id.home == item.getItemId()) {
@@ -189,6 +200,11 @@ public abstract class DrawerFragmentActivity extends AppCompatActivity implement
if (checkThemeStyleChange()) {
recreate();
}
+
+ ADsBannerView adsBannerView = findViewById(R.id.adsbanner);
+ if (adsBannerView != null) {
+ adsBannerView.resumeADs();
+ }
}
void initRootView() {
diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestAButtonFragment.java b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestAButtonFragment.java
index 23f0deef..ce837aa9 100644
--- a/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestAButtonFragment.java
+++ b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestAButtonFragment.java
@@ -13,7 +13,7 @@ import androidx.fragment.app.Fragment;
import cc.winboll.studio.libaes.R;
import cc.winboll.studio.libaes.views.AButton;
import cc.winboll.studio.libappbase.LogUtils;
-import com.hjq.toast.ToastUtils;
+import cc.winboll.studio.libappbase.ToastUtils;
public class TestAButtonFragment extends Fragment {
diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestViewPageFragment.java b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestViewPageFragment.java
index a4a33508..1d922fa1 100644
--- a/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestViewPageFragment.java
+++ b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestViewPageFragment.java
@@ -12,14 +12,13 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
-import android.widget.Toast;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.ViewPager;
import cc.winboll.studio.libaes.ImagePagerAdapter;
import cc.winboll.studio.libaes.R;
import cc.winboll.studio.libaes.views.AOHPCTCSeekBar;
import cc.winboll.studio.libappbase.LogView;
-import com.hjq.toast.ToastUtils;
+import cc.winboll.studio.libappbase.ToastUtils;
import java.util.ArrayList;
import java.util.List;
diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/utils/MimoUtils.java b/libaes/src/main/java/cc/winboll/studio/libaes/utils/MimoUtils.java
new file mode 100644
index 00000000..2c07337c
--- /dev/null
+++ b/libaes/src/main/java/cc/winboll/studio/libaes/utils/MimoUtils.java
@@ -0,0 +1,33 @@
+package cc.winboll.studio.libaes.utils;
+
+import android.content.Context;
+import android.util.DisplayMetrics;
+
+/**
+ * @Author ZhanGSKen&豆包大模型
+ * @Date 2025/11/18 15:23
+ * @Describe 米盟 MimoUtils
+ */
+public final class MimoUtils {
+ public static final String TAG = "Utils";
+
+ public static int dpToPx(Context context, float dp) {
+ DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+ return (int) (dp * displayMetrics.density + 0.5f);
+ }
+
+ public static int pxToDp(Context context, float px) {
+ DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+ return (int) (px / displayMetrics.density + 0.5f);
+ }
+
+ public static int pxToSp(Context context, float pxValue) {
+ DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+ return (int) (pxValue / displayMetrics.scaledDensity + 0.5f);
+ }
+
+ public static int spToPx(Context context, float spValue) {
+ DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+ return (int) (spValue * displayMetrics.scaledDensity + 0.5f);
+ }
+}
diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/utils/PrefUtils.java b/libaes/src/main/java/cc/winboll/studio/libaes/utils/PrefUtils.java
new file mode 100644
index 00000000..751a9e56
--- /dev/null
+++ b/libaes/src/main/java/cc/winboll/studio/libaes/utils/PrefUtils.java
@@ -0,0 +1,33 @@
+package cc.winboll.studio.libaes.utils;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+/**
+ * @Author ZhanGSKen&豆包大模型
+ * @Date 2025/11/13 06:50
+ * @Describe 应用变量保存工具
+ */
+
+public class PrefUtils {
+
+ public static final String TAG = "PrefUtils";
+
+ //
+ // 保存字符串到SharedPreferences的函数
+ //
+ public static void saveString(Context context, String key, String value) {
+ SharedPreferences sharedPreferences = context.getSharedPreferences("myPrefs", Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sharedPreferences.edit();
+ editor.putString(key, value);
+ editor.apply();
+ }
+
+ //
+ // 从SharedPreferences读取字符串的函数
+ //
+ public static String getString(Context context, String key, String defaultValue) {
+ SharedPreferences sharedPreferences = context.getSharedPreferences("myPrefs", Context.MODE_PRIVATE);
+ return sharedPreferences.getString(key, defaultValue);
+ }
+}
diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/views/ADsBannerView.java b/libaes/src/main/java/cc/winboll/studio/libaes/views/ADsBannerView.java
new file mode 100644
index 00000000..44669aa5
--- /dev/null
+++ b/libaes/src/main/java/cc/winboll/studio/libaes/views/ADsBannerView.java
@@ -0,0 +1,489 @@
+package cc.winboll.studio.libaes.views;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.os.Handler;
+import android.os.Looper;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.Toast;
+import androidx.appcompat.app.AlertDialog;
+import cc.winboll.studio.libaes.R;
+import cc.winboll.studio.libaes.utils.MimoUtils;
+import cc.winboll.studio.libappbase.GlobalApplication;
+import cc.winboll.studio.libappbase.LogUtils;
+import cc.winboll.studio.libappbase.ToastUtils;
+import com.miui.zeus.mimo.sdk.ADParams;
+import com.miui.zeus.mimo.sdk.BannerAd;
+import com.miui.zeus.mimo.sdk.MimoCustomController;
+import com.miui.zeus.mimo.sdk.MimoLocation;
+import com.miui.zeus.mimo.sdk.MimoSdk;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @Author ZhanGSKen&豆包大模型
+ * @Date 2025/11/18 14:41
+ * @Describe WinBoLL 横幅广告类
+ */
+public class ADsBannerView extends LinearLayout {
+
+ public static final String TAG = "ADsBannerView";
+
+ private static final String PRIVACY_FILE = "privacy_pfs";
+ private static final String PRIVACY_VALUE = "privacy_value";//0: 拒绝,1:赞同
+
+ private String BANNER_POS_ID = "802e356f1726f9ff39c69308bfd6f06a";
+ private String BANNER_POS_ID_WINBOLL_BETA = "d129ee5a263911f981a6dc7a9802e3e7";
+ private String BANNER_POS_ID_WINBOLL = "4ec30efdb32271765b9a4efac902828b";
+
+ /*
+ private String BANNER_POS_ID = "802e356f1726f9ff39c69308bfd6f06a";
+ private String BANNER_POS_ID_WINBOLL_BETA = "802e356f1726f9ff39c69308bfd6f06a";
+ private String BANNER_POS_ID_WINBOLL = "802e356f1726f9ff39c69308bfd6f06a";
+ */
+
+ Context mContext;
+ View mMianView;
+ SharedPreferences mSharedPreferences;
+ ViewGroup mContainer;
+ BannerAd mBannerAd;
+ List mAllBanners = new ArrayList<>();
+ // 新增:主线程Handler,确保广告操作在主线程执行
+ private Handler mMainHandler;
+
+ public ADsBannerView(Context context) {
+ super(context);
+ this.mContext = context;
+ initView();
+ }
+
+ public ADsBannerView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ this.mContext = context;
+ initView();
+ }
+
+ public ADsBannerView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ this.mContext = context;
+ initView();
+ }
+
+ public ADsBannerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ this.mContext = context;
+ initView();
+ }
+
+ void initView() {
+
+ // 初始化主线程Handler(关键:确保广告操作在主线程执行)
+ mMainHandler = new Handler(Looper.getMainLooper());
+
+ // 米盟模块:隐私协议弹窗
+ showPrivacy();
+
+ this.mMianView = inflate(this.mContext, R.layout.view_adsbanner, null);
+ mContainer = this.mMianView.findViewById(R.id.ads_container);
+ addView(this.mMianView);
+ }
+
+ Activity getActivity() {
+ try {
+ Activity activity = (Activity)this.mContext;
+ return activity;
+ } catch (Exception ex) {
+ }
+ return null;
+ }
+
+ public void resumeADs() {
+ // 修复:优化广告请求逻辑(添加生命周期判断 + 主线程执行)
+ if (getActivity() != null && !getActivity().isFinishing() && !getActivity().isDestroyed()) {
+ String privacyAgreeValue = getSharedPreferences().getString(PRIVACY_VALUE, null);
+ if (TextUtils.equals(privacyAgreeValue, String.valueOf(1))) {
+ LogUtils.i(TAG, "已同意隐私协议,开始播放米盟广告...");
+ mMainHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ //ToastUtils.show("ADs run");
+ // 再次校验生命周期,避免延迟执行时Activity已销毁
+ if (getActivity() != null && !getActivity().isFinishing() && !getActivity().isDestroyed()) {
+ fetchAd();
+ }
+ }
+ }, 1000); // 延迟1秒请求广告,提升页面加载体验
+ }
+ }
+ }
+
+ /**
+ * 释放广告资源(关键:避免内存泄漏和空Context调用)
+ */
+ public void releaseAdResources() {
+ LogUtils.d(TAG, "releaseAdResources()");
+
+ // 移除Handler回调
+ if (mMainHandler != null) {
+ mMainHandler.removeCallbacksAndMessages(null);
+ }
+
+ // 销毁所有广告实例
+ if (mAllBanners != null && !mAllBanners.isEmpty()) {
+ for (BannerAd ad : mAllBanners) {
+ if (ad != null) {
+ ad.destroy();
+ }
+ }
+ mAllBanners.clear();
+ }
+ // 置空当前广告引用
+ mBannerAd = null;
+ // 移除广告容器中的视图
+ if (mContainer != null) {
+ mContainer.removeAllViews();
+ }
+ }
+
+ /**
+ * 显示广告(核心修复:传递安全的Context + 生命周期校验)
+ */
+ private void showAd() {
+ LogUtils.d(TAG, "showAd()");
+ // 1. 生命周期校验:避免Activity已销毁时操作UI
+ if (getActivity() == null || getActivity().isFinishing() || getActivity().isDestroyed()) {
+ LogUtils.e(TAG, "showAd: Activity is finishing or destroyed");
+ return;
+ }
+ // 2. 非空校验:广告实例和容器
+ if (mBannerAd == null || mContainer == null) {
+ LogUtils.e(TAG, "showAd: BannerAd or Container is null");
+ return;
+ }
+ // 3. 创建广告容器(使用ApplicationContext避免内存泄漏)
+ final FrameLayout container = new FrameLayout(getActivity().getApplicationContext());
+ container.setPadding(0, 0, 0, MimoUtils.dpToPx(getActivity(), 10));
+ mContainer.addView(container, new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.WRAP_CONTENT
+ ));
+
+// if (mIsBiddingWin) {
+// mBannerAd.setPrice(getPrice());
+// }
+ // 4. 显示广告:传递ApplicationContext,避免Activity Context失效
+ mBannerAd.showAd(getActivity(), container, new BannerAd.BannerInteractionListener() {
+ @Override
+ public void onAdClick() {
+ LogUtils.d(TAG, "onAdClick");
+ }
+
+ @Override
+ public void onAdShow() {
+ LogUtils.d(TAG, "onAdShow");
+ }
+
+ @Override
+ public void onAdDismiss() {
+ LogUtils.d(TAG, "onAdDismiss");
+ // 修复:移除容器时校验Activity状态
+ if (getActivity() != null && !getActivity().isFinishing() && !getActivity().isDestroyed() && mContainer != null) {
+ mContainer.removeView(container);
+ }
+ }
+
+ @Override
+ public void onRenderSuccess() {
+ LogUtils.d(TAG, "onRenderSuccess");
+ }
+
+ @Override
+ public void onRenderFail(int code, String msg) {
+ LogUtils.e(TAG, "onRenderFail errorCode " + code + " errorMsg " + msg);
+ // 修复:渲染失败时移除容器
+ if (getActivity() != null && !getActivity().isFinishing() && !getActivity().isDestroyed() && mContainer != null) {
+ mContainer.removeView(container);
+ }
+ }
+ });
+ }
+
+ /**
+ * 请求广告(核心修复:Context安全校验 + 异常捕获 + 资源管理)
+ */
+ private void fetchAd() {
+ LogUtils.d(TAG, "fetchAd()");
+ // 1. 双重校验:Activity未销毁 + Context非空
+ if (getActivity() == null || getActivity().isFinishing() || getActivity().isDestroyed() || getActivity().getApplicationContext() == null) {
+ LogUtils.e(TAG, "fetchAd: Invalid Context or Activity state");
+ return;
+ }
+ // 2. 释放之前的广告资源,避免内存泄漏
+ if (mBannerAd != null) {
+ mBannerAd.destroy();
+ }
+ // 3. 初始化广告(使用ApplicationContext,避免Activity Context失效)
+ try {
+ mBannerAd = new BannerAd();
+ mAllBanners.add(mBannerAd);
+ } catch (Exception e) {
+ LogUtils.e(TAG, "fetchAd: Init BannerAd failed", e);
+ return;
+ }
+ // 4. 设置下载监听
+ mBannerAd.setDownLoadListener(new BannerAd.BannerDownloadListener() {
+ @Override
+ public void onDownloadStarted() {
+ LogUtils.d(TAG, "onDownloadStarted");
+ }
+
+ @Override
+ public void onDownloadPaused() {
+ LogUtils.d(TAG, "onDownloadPaused");
+ }
+
+ @Override
+ public void onDownloadFailed(int errorCode) {
+ String msg = "onDownloadFailed, errorCode = " + errorCode;
+ LogUtils.d(TAG, msg);
+ //ToastUtils.show(msg);
+ }
+
+ @Override
+ public void onDownloadFinished() {
+ LogUtils.d(TAG, "onDownloadFinished");
+ }
+
+ @Override
+ public void onDownloadProgressUpdated(int progress) {
+ LogUtils.d(TAG, "onDownloadProgressUpdated " + progress + "%");
+ }
+
+ @Override
+ public void onInstallFailed(int errorCode) {
+ LogUtils.d(TAG, "onInstallFailed, errorCode = " + errorCode);
+ }
+
+ @Override
+ public void onInstallStart() {
+ LogUtils.d(TAG, "onInstallStart");
+ }
+
+ @Override
+ public void onInstallSuccess() {
+ LogUtils.d(TAG, "onInstallSuccess");
+ }
+
+ @Override
+ public void onDownloadCancel() {
+ LogUtils.d(TAG, "onDownloadCancel");
+ }
+ });
+
+ // 5. 构建广告参数并请求
+ String currentAD_ID = getAD_ID();
+ LogUtils.d(TAG, String.format("currentAD_ID = %s", currentAD_ID));
+ ADParams params = new ADParams.Builder().setUpId(currentAD_ID).build();
+ mBannerAd.loadAd(params, new BannerAd.BannerLoadListener() {
+ @Override
+ public void onBannerAdLoadSuccess() {
+ LogUtils.d(TAG, "onBannerAdLoadSuccess()");
+ // 修复:广告加载成功后校验Activity状态
+ if (getActivity() != null && !getActivity().isFinishing() && !getActivity().isDestroyed()) {
+ showAd();
+ }
+ }
+
+ @Override
+ public void onAdLoadFailed(int errorCode, String errorMsg) {
+ String msg = "onAdLoadFailed: errorCode = " + errorCode + ", errorMsg = " + errorMsg;
+ LogUtils.d(TAG, msg);
+ if (errorCode == 300219) {
+ // 如果是广告拉取错误就提示一下
+ ToastUtils.show(String.format("米盟 SDK Error Code : %d", errorCode));
+ }
+ removeAllBanners();
+ }
+ });
+ }
+
+ void removeAllBanners() {
+ // 修复:加载失败时移除当前广告实例
+ if (mAllBanners.contains(mBannerAd)) {
+ mAllBanners.remove(mBannerAd);
+ }
+ mBannerAd.destroy();
+ mBannerAd = null;
+ }
+
+ /**
+ * 根据当前秒数获取广告ID(原逻辑保留)
+ */
+ private String getAD_ID() {
+ long currentSecond = System.currentTimeMillis() / 1000;
+ return (currentSecond % 2 == 0) ? BANNER_POS_ID :
+ (GlobalApplication.isDebugging() ? BANNER_POS_ID_WINBOLL_BETA : BANNER_POS_ID_WINBOLL);
+ }
+
+ /**
+ * 获取广告价格(原逻辑保留,添加空指针校验)
+ */
+ private long getPrice() {
+ if (mBannerAd == null) {
+ return 0;
+ }
+ Map map = mBannerAd.getMediaExtraInfo();
+ if (map == null || map.isEmpty() || !map.containsKey("price")) {
+ LogUtils.w(TAG, "getPrice: media extra info is null or no price key");
+ return 0;
+ }
+ Object priceObj = map.get("price");
+ if (priceObj instanceof Long) {
+ return (Long) priceObj;
+ } else if (priceObj instanceof Integer) {
+ return ((Integer) priceObj).longValue();
+ } else {
+ LogUtils.e(TAG, "getPrice: price type is invalid");
+ return 0;
+ }
+ }
+
+ /**
+ * 显示隐私协议弹窗(原逻辑保留,优化Context使用)
+ */
+ private void showPrivacy() {
+ // 校验Activity状态,避免弹窗泄露
+ if (getActivity() == null || getActivity().isFinishing() || getActivity().isDestroyed()) {
+ return;
+ }
+ String privacyAgreeValue = getSharedPreferences().getString(PRIVACY_VALUE, null);
+ if (TextUtils.equals(privacyAgreeValue, String.valueOf(0))) {
+ LogUtils.i(TAG, "已拒绝隐私协议,广告已处于不可用状态...");
+ Toast.makeText(getActivity().getApplicationContext(), "已拒绝隐私协议,广告已处于不可用状态", Toast.LENGTH_SHORT).show();
+ return;
+ }
+ if (TextUtils.equals(privacyAgreeValue, String.valueOf(1))) {
+ LogUtils.i(TAG, "已同意隐私协议,开始初始化米盟SDK...");
+ initMimoSdk();
+ return;
+ }
+ LogUtils.i(TAG, "开始弹出隐私协议...");
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle("用户须知");
+ builder.setMessage("小米广告SDK隐私政策: https://dev.mi.com/distribute/doc/details?pId=1688, 请复制到浏览器查看");
+ builder.setIcon(R.drawable.ic_launcher);
+ builder.setCancelable(false); // 点击对话框以外的区域不消失
+ builder.setPositiveButton("同意", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ getSharedPreferences().edit()
+ .putString(PRIVACY_VALUE, String.valueOf(1))
+ .apply();
+ initMimoSdk();
+ dialog.dismiss();
+ }
+ });
+ builder.setNegativeButton("拒绝", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ getSharedPreferences().edit()
+ .putString(PRIVACY_VALUE, String.valueOf(0))
+ .apply();
+ dialog.dismiss();
+ }
+ });
+ AlertDialog dialog = builder.create();
+
+ // 配置弹窗位置(底部全屏)
+ Window window = dialog.getWindow();
+ if (window != null) {
+ window.setGravity(Gravity.BOTTOM);
+ WindowManager m = getActivity().getWindowManager();
+ Display d = m.getDefaultDisplay();
+ WindowManager.LayoutParams p = window.getAttributes();
+ p.width = d.getWidth();
+ window.setAttributes(p);
+ }
+ dialog.show();
+ }
+
+ /**
+ * 初始化米盟SDK(核心修复:传递ApplicationContext + 异常捕获)
+ */
+ private void initMimoSdk() {
+ // 1. 安全获取ApplicationContext,避免Activity Context失效
+ Context appContext = getActivity().getApplicationContext();
+ if (appContext == null) {
+ LogUtils.e(TAG, "initMimoSdk: ApplicationContext is null");
+ return;
+ }
+ // 2. 初始化SDK,捕获异常避免崩溃
+ try {
+ MimoSdk.init(appContext, new MimoCustomController() {
+ @Override
+ public boolean isCanUseLocation() {
+ return true;
+ }
+
+ @Override
+ public MimoLocation getMimoLocation() {
+ return null;
+ }
+
+ @Override
+ public boolean isCanUseWifiState() {
+ return true;
+ }
+
+ @Override
+ public boolean alist() {
+ return true;
+ }
+ }, new MimoSdk.InitCallback() {
+ @Override
+ public void success() {
+ LogUtils.d(TAG, "MimoSdk init success");
+ }
+
+ @Override
+ public void fail(int code, String msg) {
+ LogUtils.e(TAG, "MimoSdk init fail, code=" + code + ",msg=" + msg);
+ }
+ });
+ MimoSdk.setDebugOn(true);
+ } catch (Exception e) {
+ LogUtils.e(TAG, "initMimoSdk: init failed", e);
+ }
+ }
+
+
+ /**
+ * 获取SharedPreferences实例(原逻辑保留,添加空指针校验)
+ */
+ SharedPreferences getSharedPreferences() {
+ if (mSharedPreferences == null) {
+ // 修复:使用ApplicationContext获取SharedPreferences,避免Activity Context泄露
+ Context appContext = getActivity().getApplicationContext();
+ if (appContext != null) {
+ mSharedPreferences = appContext.getSharedPreferences(PRIVACY_FILE, Context.MODE_PRIVATE);
+ } else {
+ LogUtils.e(TAG, "getSharedPreferences: ApplicationContext is null");
+ // 降级方案:若ApplicationContext为空,使用Activity Context(仅作兼容)
+ mSharedPreferences = getActivity().getSharedPreferences(PRIVACY_FILE, Context.MODE_PRIVATE);
+ }
+ }
+ return mSharedPreferences;
+ }
+}
diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/views/AboutView.java b/libaes/src/main/java/cc/winboll/studio/libaes/views/AboutView.java
index 41ddb8d0..fe6f076f 100644
--- a/libaes/src/main/java/cc/winboll/studio/libaes/views/AboutView.java
+++ b/libaes/src/main/java/cc/winboll/studio/libaes/views/AboutView.java
@@ -12,7 +12,6 @@ import android.content.res.TypedArray;
import android.net.Uri;
import android.os.Message;
import android.util.AttributeSet;
-import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
@@ -20,11 +19,11 @@ import cc.winboll.studio.libaes.R;
import cc.winboll.studio.libaes.dialogs.YesNoAlertDialog;
import cc.winboll.studio.libaes.models.APPInfo;
import cc.winboll.studio.libaes.utils.AppVersionUtils;
+import cc.winboll.studio.libaes.utils.PrefUtils;
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.libappbase.LogUtils;
-import cc.winboll.studio.libapputils.utils.PrefUtils;
-import com.hjq.toast.ToastUtils;
+import cc.winboll.studio.libappbase.ToastUtils;
import java.io.IOException;
import mehdi.sakout.aboutpage.AboutPage;
import mehdi.sakout.aboutpage.Element;
@@ -108,7 +107,7 @@ public class AboutView extends LinearLayout {
mszAppDescription = mAPPInfo.getAppDescription();
mnAppIcon = mAPPInfo.getAppIcon();
- mszWinBoLLServerHost = GlobalApplication.isDebuging() ? "https://yun-preivew.winboll.cc": "https://yun.winboll.cc";
+ mszWinBoLLServerHost = GlobalApplication.isDebugging() ? "https://yun-preivew.winboll.cc": "https://yun.winboll.cc";
try {
mszAppVersionName = _mContext.getPackageManager().getPackageInfo(_mContext.getPackageName(), 0).versionName;
@@ -229,7 +228,7 @@ public class AboutView extends LinearLayout {
// 定义应用调试按钮
//
Element elementAppMode;
- if (GlobalApplication.isDebuging()) {
+ if (GlobalApplication.isDebugging()) {
elementAppMode = new Element(_mContext.getString(R.string.app_normal), R.drawable.ic_winboll);
elementAppMode.setOnClickListener(mAppNormalOnClickListener);
} else {
@@ -263,8 +262,8 @@ public class AboutView extends LinearLayout {
if (intent != null) {
//intent.setAction(cc.winboll.studio.libapputils.intent.action.DEBUGVIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- GlobalApplication.setIsDebuging(true);
- GlobalApplication.saveDebugStatus(_mContext);
+ GlobalApplication.setIsDebugging(true);
+ GlobalApplication.saveDebugStatus((GlobalApplication)_mContext.getApplicationContext());
WinBoLLActivityManager.getInstance().finishAll();
context.startActivity(intent);
@@ -275,8 +274,8 @@ public class AboutView extends LinearLayout {
Intent intent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
if (intent != null) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- GlobalApplication.setIsDebuging(false);
- GlobalApplication.saveDebugStatus(_mContext);
+ GlobalApplication.setIsDebugging(false);
+ GlobalApplication.saveDebugStatus((GlobalApplication)_mContext.getApplicationContext());
WinBoLLActivityManager.getInstance().finishAll();
context.startActivity(intent);
@@ -301,7 +300,7 @@ public class AboutView extends LinearLayout {
String szUrl = mszWinBoLLServerHost + "/studio/details.php?app=" + mszAppAPKFolderName;
// 构建包含认证信息的请求
String credential = "";
- if (GlobalApplication.isDebuging()) {
+ if (GlobalApplication.isDebugging()) {
credential = Credentials.basic(metDevUserName.getText().toString(), metDevUserPassword.getText().toString());
PrefUtils.saveString(_mContext, "metDevUserName", metDevUserName.getText().toString());
PrefUtils.saveString(_mContext, "metDevUserPassword", metDevUserPassword.getText().toString());
diff --git a/libaes/src/main/res/layout/activity_drawerfragment.xml b/libaes/src/main/res/layout/activity_drawerfragment.xml
index 8d976ab5..22ce6efb 100644
--- a/libaes/src/main/res/layout/activity_drawerfragment.xml
+++ b/libaes/src/main/res/layout/activity_drawerfragment.xml
@@ -10,7 +10,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/activitydrawerfragmentASupportToolbar1"/>
-
+
+
+
+
diff --git a/libaes/src/main/res/layout/view_adsbanner.xml b/libaes/src/main/res/layout/view_adsbanner.xml
new file mode 100644
index 00000000..286d1f88
--- /dev/null
+++ b/libaes/src/main/res/layout/view_adsbanner.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
diff --git a/libaes/src/main/res/menu/toolbar_studio_debug.xml b/libaes/src/main/res/menu/toolbar_studio_debug.xml
new file mode 100644
index 00000000..4471301c
--- /dev/null
+++ b/libaes/src/main/res/menu/toolbar_studio_debug.xml
@@ -0,0 +1,35 @@
+
+
diff --git a/libaes/src/main/res/values/strings.xml b/libaes/src/main/res/values/strings.xml
index 5f94d4c4..f9f1d392 100644
--- a/libaes/src/main/res/values/strings.xml
+++ b/libaes/src/main/res/values/strings.xml
@@ -12,5 +12,10 @@
GoldenTheme
MemorTheme
TaoTheme
-
+
+ Click here is switch to Normal APP
+ Click here is switch to APP DEBUG
+ GITEA HOME
+ APP UPDATE
+
diff --git a/libaes/src/main/res/xml/file_paths.xml b/libaes/src/main/res/xml/file_paths.xml
new file mode 100644
index 00000000..21bd1b8b
--- /dev/null
+++ b/libaes/src/main/res/xml/file_paths.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/libaes/src/main/res/xml/network_security_config.xml b/libaes/src/main/res/xml/network_security_config.xml
new file mode 100644
index 00000000..ba3f407a
--- /dev/null
+++ b/libaes/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,16 @@
+
+
+
+
+ winboll.cc
+
+
+
+
+
+
+
+
+
+
+