diff --git a/positions/build.properties b/positions/build.properties
index 4c8791f3..251798ae 100644
--- a/positions/build.properties
+++ b/positions/build.properties
@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
-#Thu Nov 13 14:05:41 HKT 2025
+#Thu Nov 13 08:15:14 GMT 2025
stageCount=1
libraryProject=
baseVersion=15.11
publishVersion=15.11.0
-buildCount=0
+buildCount=9
baseBetaVersion=15.11.1
diff --git a/positions/src/main/AndroidManifest.xml b/positions/src/main/AndroidManifest.xml
index f9b4719d..1c69bdb8 100644
--- a/positions/src/main/AndroidManifest.xml
+++ b/positions/src/main/AndroidManifest.xml
@@ -12,6 +12,8 @@
+
+
+ android:label="@string/app_name"
+ android:exported="true">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -104,7 +123,18 @@
-
+
+
+
+
+
+
diff --git a/positions/src/main/java/cc/winboll/studio/positions/MainActivity.java b/positions/src/main/java/cc/winboll/studio/positions/MainActivity.java
index f9ef47f0..e1deb539 100644
--- a/positions/src/main/java/cc/winboll/studio/positions/MainActivity.java
+++ b/positions/src/main/java/cc/winboll/studio/positions/MainActivity.java
@@ -6,6 +6,7 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
+import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CompoundButton;
@@ -20,9 +21,10 @@ import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.positions.activities.LocationActivity;
import cc.winboll.studio.positions.activities.WinBoLLActivity;
-import cc.winboll.studio.positions.utils.AppConfigsUtil;
-import cc.winboll.studio.positions.utils.ServiceUtil;
import cc.winboll.studio.positions.utils.APPPlusUtils;
+import cc.winboll.studio.positions.utils.AppConfigsUtil;
+import cc.winboll.studio.positions.utils.JsonShareHandler;
+import cc.winboll.studio.positions.utils.ServiceUtil;
/**
* 主页面:仅负责
@@ -89,6 +91,8 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
setContentView(R.layout.activity_main); // 关联主页面布局
// 处理应用级别的切换请求
handleSwitchRequest();
+ // 处理启动时的分享 Intent
+ handleShareIntent(getIntent());
// 设置当前应用级别
App.setAppLevel(this);
@@ -122,6 +126,30 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
}
}
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ // 处理后续接收的分享 Intent(如应用已在后台)
+ handleShareIntent(intent);
+ }
+
+ private void handleShareIntent(Intent intent) {
+ if (intent != null && Intent.ACTION_SEND.equals(intent.getAction())) {
+ // 调用工具类,弹出确认对话框
+ JsonShareHandler.handleSharedJsonWithConfirm(this, intent, new JsonShareHandler.ConfirmCallback() {
+ @Override
+ public void onConfirm(boolean isConfirm) {
+ // 回调处理:isConfirm 为 true 表示接收并保存,false 表示取消
+ if (!isConfirm) {
+ Log.d("MainActivity", "用户取消接收文件");
+ // 可添加取消后的逻辑(如关闭页面)
+ // finish();
+ }
+ }
+ });
+ }
+ }
+
@Override
protected void onDestroy() {
super.onDestroy();
diff --git a/positions/src/main/java/cc/winboll/studio/positions/MainActivityLaojun.java b/positions/src/main/java/cc/winboll/studio/positions/MainActivityLaojun.java
new file mode 100644
index 00000000..15b5da56
--- /dev/null
+++ b/positions/src/main/java/cc/winboll/studio/positions/MainActivityLaojun.java
@@ -0,0 +1,22 @@
+package cc.winboll.studio.positions;
+import android.os.Bundle;
+import cc.winboll.studio.libappbase.LogUtils;
+import cc.winboll.studio.libappbase.ToastUtils;
+
+/**
+ * @Author ZhanGSKen&豆包大模型
+ * @Date 2025/11/13 15:21
+ * @Describe MainActivityLaojun
+ */
+public class MainActivityLaojun extends MainActivity {
+
+ public static final String TAG = "MainActivityLaojun";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ ToastUtils.show("道法自然");
+ LogUtils.d(TAG, "玩法归臻");
+ super.onCreate(savedInstanceState);
+ }
+
+}
diff --git a/positions/src/main/java/cc/winboll/studio/positions/utils/JsonShareHandler.java b/positions/src/main/java/cc/winboll/studio/positions/utils/JsonShareHandler.java
new file mode 100644
index 00000000..13095c6e
--- /dev/null
+++ b/positions/src/main/java/cc/winboll/studio/positions/utils/JsonShareHandler.java
@@ -0,0 +1,241 @@
+package cc.winboll.studio.positions.utils;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+import android.provider.MediaStore;
+import android.util.Log;
+import android.widget.Toast;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * @Author ZhanGSKen&豆包大模型
+ * @Date 2025/11/13 15:42
+ * @Describe JsonShareHandler
+ * 外部 JSON 文件分享处理工具类
+ * 功能:接收外部分享的 .json 文件,弹出确认对话框,保存到外部存储 files/BaseBean 目录
+ */
+public class JsonShareHandler {
+ private static final String TAG = "JsonShareHandler";
+ private static final String TARGET_DIR = "BaseBean";
+ private static final String MIME_TYPE_JSON = "application/json";
+ private static final String FILE_SUFFIX_JSON = ".json";
+ // 对话框回调接口(Java7 无 Lambda,用接口实现)
+ public interface ConfirmCallback {
+ void onConfirm(boolean isConfirm);
+ }
+
+ /**
+ * 处理外部分享的 Intent,先弹出确认对话框,再决定是否接收文件
+ * @param context 上下文(需为 Activity,否则无法弹出对话框)
+ * @param intent 分享 Intent
+ * @param callback 确认结果回调(用于 Activity 处理后续逻辑)
+ */
+ public static void handleSharedJsonWithConfirm(final Context context, final Intent intent, final ConfirmCallback callback) {
+ if (context == null || intent == null || callback == null) {
+ Log.e(TAG, "参数为空,处理失败");
+ if (callback != null) callback.onConfirm(false);
+ return;
+ }
+
+ // 1. 先验证 Intent 合法性(提前过滤无效分享)
+ String action = intent.getAction();
+ String type = intent.getType();
+ if (!Intent.ACTION_SEND.equals(action) || type == null) {
+ Log.e(TAG, "非文件分享 Intent");
+ Toast.makeText(context, "不支持的分享类型", Toast.LENGTH_SHORT).show();
+ callback.onConfirm(false);
+ return;
+ }
+
+ // 2. 弹出确认对话框
+ new AlertDialog.Builder(context)
+ .setTitle("接收 JSON 文件")
+ .setMessage("是否接收并保存该 JSON 文件?")
+ .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ // 3. 点击 Yes,处理文件保存
+ String savedPath = handleSharedJsonFile(context, intent);
+ if (savedPath != null) {
+ Toast.makeText(context, "文件保存成功:" + savedPath, Toast.LENGTH_LONG).show();
+ callback.onConfirm(true);
+ } else {
+ Toast.makeText(context, "文件保存失败", Toast.LENGTH_SHORT).show();
+ callback.onConfirm(false);
+ }
+ }
+ })
+ .setNegativeButton("No", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ // 4. 点击 No,直接退出处理
+ callback.onConfirm(false);
+ }
+ })
+ .setCancelable(false) // 不可点击外部取消
+ .show();
+ }
+
+ /**
+ * 核心文件处理逻辑(原有功能,无修改)
+ */
+ private static String handleSharedJsonFile(Context context, Intent intent) {
+ String action = intent.getAction();
+ String type = intent.getType();
+
+ // 验证 JSON 格式
+ if (!MIME_TYPE_JSON.equals(type) && !type.contains("json")) {
+ Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
+ if (uri == null || !getFileNameFromUri(context, uri).endsWith(FILE_SUFFIX_JSON)) {
+ Log.e(TAG, "接收的文件不是 JSON 格式");
+ return null;
+ }
+ }
+
+ Uri sharedUri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
+ if (sharedUri == null) {
+ Log.e(TAG, "未获取到分享的文件 Uri");
+ return null;
+ }
+
+ try {
+ // 创建保存目录
+ File saveDir = getTargetSaveDir(context);
+ if (!saveDir.exists() && !saveDir.mkdirs()) {
+ Log.e(TAG, "创建保存目录失败:" + saveDir.getAbsolutePath());
+ return null;
+ }
+
+ // 解析文件名(兼容低版本)
+ String fileName = getFileNameFromUri(context, sharedUri);
+ if (fileName == null || !fileName.endsWith(FILE_SUFFIX_JSON)) {
+ fileName = "default_" + System.currentTimeMillis() + FILE_SUFFIX_JSON;
+ Log.w(TAG, "文件名解析失败,使用默认名称:" + fileName);
+ }
+
+ // 复制文件
+ File targetFile = new File(saveDir, fileName);
+ boolean copySuccess = copyFileFromUri(context, sharedUri, targetFile);
+ return copySuccess ? targetFile.getAbsolutePath() : null;
+
+ } catch (Exception e) {
+ Log.e(TAG, "处理分享文件异常:" + e.getMessage());
+ return null;
+ }
+ }
+
+ /**
+ * 获取目标保存目录(兼容 Android 10+ 分区存储)
+ */
+ private static File getTargetSaveDir(Context context) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ return new File(context.getExternalFilesDir(null), TARGET_DIR);
+ } else {
+ return new File(
+ Environment.getExternalStorageDirectory() + File.separator +
+ "Android" + File.separator +
+ "data" + File.separator +
+ context.getPackageName() + File.separator +
+ "files" + File.separator +
+ TARGET_DIR
+ );
+ }
+ }
+
+ /**
+ * 从 Uri 解析文件名(兼容所有 Android 版本)
+ */
+ private static String getFileNameFromUri(Context context, Uri uri) {
+ if (uri == null) return null;
+
+ // 1. 文件 Uri(file:// 开头)
+ if ("file".equals(uri.getScheme())) {
+ return new File(uri.getPath()).getName();
+ }
+
+ // 2. 内容 Uri(content:// 开头)
+ if ("content".equals(uri.getScheme())) {
+ Cursor cursor = null;
+ try {
+ cursor = context.getContentResolver().query(
+ uri,
+ new String[]{MediaStore.MediaColumns.DISPLAY_NAME},
+ null,
+ null,
+ null
+ );
+ if (cursor != null && cursor.moveToFirst()) {
+ int nameIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME);
+ if (nameIndex != -1) {
+ return cursor.getString(nameIndex);
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "解析内容 Uri 文件名失败:" + e.getMessage());
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+ }
+
+ // 3. 解析失败,返回默认名称
+ String lastPathSegment = uri.getLastPathSegment();
+ return lastPathSegment != null ? lastPathSegment : "unknown.json";
+ }
+
+ /**
+ * 复制 Uri 指向的文件到目标路径
+ */
+ private static boolean copyFileFromUri(Context context, Uri sourceUri, File targetFile) {
+ InputStream inputStream = null;
+ OutputStream outputStream = null;
+ try {
+ inputStream = context.getContentResolver().openInputStream(sourceUri);
+ if (inputStream == null) {
+ Log.e(TAG, "无法打开源文件输入流");
+ return false;
+ }
+
+ outputStream = new FileOutputStream(targetFile);
+ byte[] buffer = new byte[1024 * 4];
+ int length;
+ while ((length = inputStream.read(buffer)) != -1) {
+ outputStream.write(buffer, 0, length);
+ }
+ outputStream.flush();
+ Log.d(TAG, "文件保存成功:" + targetFile.getAbsolutePath());
+ return true;
+
+ } catch (IOException e) {
+ Log.e(TAG, "文件复制异常:" + e.getMessage());
+ return false;
+ } finally {
+ try {
+ if (inputStream != null) inputStream.close();
+ if (outputStream != null) outputStream.close();
+ } catch (IOException e) {
+ Log.e(TAG, "关闭流异常:" + e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * 检查外部存储是否可用
+ */
+ public static boolean isExternalStorageAvailable() {
+ String state = Environment.getExternalStorageState();
+ return Environment.MEDIA_MOUNTED.equals(state);
+ }
+}
+
diff --git a/positions/src/main/res/xml/file_paths.xml b/positions/src/main/res/xml/file_paths.xml
new file mode 100644
index 00000000..802e4cc6
--- /dev/null
+++ b/positions/src/main/res/xml/file_paths.xml
@@ -0,0 +1,6 @@
+
+
+
+