From 04b4e489e4e34489e009ef0169371c2ec682f051 Mon Sep 17 00:00:00 2001 From: frank wang <425294756@qq.com> Date: Mon, 13 Oct 2025 17:40:46 +0800 Subject: [PATCH 01/12] =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 3 +- .../java/com/pxkj/jwzs/FirstActivity.java | 152 ++++++++---------- 2 files changed, 67 insertions(+), 88 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ed93d76..e56234b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,8 +2,9 @@ - + + MIME_TYPES = new HashMap<>(); static { MIME_TYPES.put("js", "text/javascript"); - MIME_TYPES.put("mjs", "text/javascript"); // 模块JavaScript + MIME_TYPES.put("mjs", "text/javascript"); MIME_TYPES.put("css", "text/css"); MIME_TYPES.put("html", "text/html"); MIME_TYPES.put("png", "image/png"); @@ -58,31 +59,11 @@ public class FirstActivity extends BaseActivity { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - // 初始化Toolbar -// androidx.appcompat.widget.Toolbar toolbar = findViewById(R.id.toolbar); -// setSupportActionBar(toolbar); // 关键:将Toolbar设为ActionBar - - // 显示返回按钮 -// if (getSupportActionBar() != null) { -// getSupportActionBar().setDisplayHomeAsUpEnabled(true); -// getSupportActionBar().setDisplayShowHomeEnabled(true); -// } - - // 设置返回按钮点击事件 -// toolbar.setNavigationOnClickListener(v -> { -// if (webView.canGoBack()) { -// webView.goBack(); -// } else { -// finish(); -// } -// }); - initWebView(); loadLocalH5(); verifyAssets(); } - @Override public void onBackPressed() { if (webView.canGoBack()) { @@ -91,26 +72,11 @@ public class FirstActivity extends BaseActivity { super.onBackPressed(); } } + private void verifyAssets() { try { String[] files = getAssets().list("web"); Log.d(TAG, "Assets/web 目录内容: " + java.util.Arrays.toString(files)); - - if (files != null) { - boolean hasIndexHtml = false; - boolean hasAssetsDir = false; - for (String file : files) { - if (file.equals("index.html")) hasIndexHtml = true; - if (file.equals("assets")) hasAssetsDir = true; - } - Log.d(TAG, "index.html 存在: " + hasIndexHtml); - Log.d(TAG, "assets 目录存在: " + hasAssetsDir); - - if (hasAssetsDir) { - String[] assetFiles = getAssets().list("web/assets"); - Log.d(TAG, "Assets/web/assets 目录内容: " + java.util.Arrays.toString(assetFiles)); - } - } } catch (IOException e) { Log.e(TAG, "无法读取 assets 目录", e); } @@ -120,7 +86,6 @@ public class FirstActivity extends BaseActivity { webView = findViewById(R.id.webview); WebSettings settings = webView.getSettings(); - // 基本设置 settings.setJavaScriptEnabled(true); settings.setDomStorageEnabled(true); settings.setDatabaseEnabled(true); @@ -130,30 +95,21 @@ public class FirstActivity extends BaseActivity { settings.setLoadsImagesAutomatically(true); settings.setBlockNetworkImage(false); settings.setBlockNetworkLoads(false); - - // 缓存设置 settings.setCacheMode(WebSettings.LOAD_DEFAULT); - // 跨域设置 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { settings.setAllowFileAccessFromFileURLs(true); settings.setAllowUniversalAccessFromFileURLs(true); } - - // 混合内容设置 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); } - - // 对于Android 10+的暗黑模式设置 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { settings.setForceDark(WebSettings.FORCE_DARK_OFF); } - // 添加JS接口 webView.addJavascriptInterface(new JsBridge(this), "AndroidBridge"); - // 启用WebView调试 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { WebView.setWebContentsDebuggingEnabled(true); } @@ -168,16 +124,23 @@ public class FirstActivity extends BaseActivity { @Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { - // 忽略SSL错误(仅用于开发环境) handler.proceed(); } + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + if (isDownloadUrl(url)) { + downloadFile(url); + return true; + } + return super.shouldOverrideUrlLoading(view, url); + } + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Override public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { String url = request.getUrl().toString(); log(TAG, "拦截请求: " + url); - return handleResourceRequest(url); } @@ -194,52 +157,37 @@ public class FirstActivity extends BaseActivity { if (url.startsWith("file:///android_asset/")) { try { String assetPath = url.replace("file:///android_asset/", ""); - - // 标准化路径处理 - assetPath = assetPath.replace("web/./", "web/") - .replace("/./", "/"); - - // 确保路径以web/开头 - if (!assetPath.startsWith("web/")) { - assetPath = "web/" + assetPath; - } + assetPath = assetPath.replace("web/./", "web/").replace("/./", "/"); + if (!assetPath.startsWith("web/")) assetPath = "web/" + assetPath; InputStream inputStream = getAssets().open(assetPath); String mimeType = getMimeTypeForUrl(url); - log(TAG, "成功加载资源: " + assetPath + " | MIME: " + mimeType); return new WebResourceResponse(mimeType, "UTF-8", inputStream); } catch (IOException e) { log(TAG, "资源加载失败: " + url + ", 错误: " + e.getMessage()); - return null; // 返回null让WebView尝试其他方式加载 + return null; } } return null; } }); + + // DownloadListener 备用 + webView.setDownloadListener((url, userAgent, contentDisposition, mimeType, contentLength) -> { + downloadFile(url); + }); } private String getMimeTypeForUrl(String url) { - // 特殊处理模块脚本 - if (url.contains("index-DJSXJc-t.js") || url.contains(".mjs") || - (url.contains("module") && url.endsWith(".js"))) { + if (url.contains("index-DJSXJc-t.js") || url.contains(".mjs") || (url.contains("module") && url.endsWith(".js"))) { return "text/javascript"; } - - // 移除URL中的查询参数和哈希 String cleanUrl = url.split("[?#]")[0]; - - // 从文件扩展名获取MIME类型 String extension = ""; int dotIndex = cleanUrl.lastIndexOf('.'); - if (dotIndex > 0) { - extension = cleanUrl.substring(dotIndex + 1).toLowerCase(); - } - - // 从预设映射中获取MIME类型 + if (dotIndex > 0) extension = cleanUrl.substring(dotIndex + 1).toLowerCase(); String mimeType = MIME_TYPES.get(extension); - - // 默认值 return mimeType != null ? mimeType : "text/plain"; } @@ -251,13 +199,46 @@ public class FirstActivity extends BaseActivity { private void loadLocalH5() { runOnUiThread(() -> { - // 直接使用loadUrl加载,确保路径解析正确 String localUrl = "file:///android_asset/web/index.html"; log(TAG, "使用 loadUrl 加载: " + localUrl); webView.loadUrl(localUrl); }); } + private boolean isDownloadUrl(String url) { + if (TextUtils.isEmpty(url)) return false; + + return true; + +// return url.endsWith(".pdf") +// || url.endsWith(".doc") +// || url.endsWith(".docx") +// || url.endsWith(".xls") +// || url.endsWith(".xlsx") +// || url.contains("/api/file/"); + } + + private void downloadFile(String url) { + try { + DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); + String fileName = URLUtil.guessFileName(url, null, null); + request.setTitle(fileName); + request.setDescription("正在下载文件..."); + request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); + request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName); + request.allowScanningByMediaScanner(); + request.addRequestHeader("User-Agent", System.getProperty("http.agent")); + + DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); + dm.enqueue(request); + + Toast.makeText(this, "文件已开始下载,完成后可在通知栏查看", Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(this, "下载失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + } + public static class JsBridge { private final WeakReference activityRef; @@ -271,8 +252,7 @@ public class FirstActivity extends BaseActivity { if (activity != null) { showLog("[Android] 开始获取资源地址..."); String baseUrl = SpUtils.getString(activity, "TARGET_URL", ""); - String logMsg = "[Android] 获取到资源地址: " + baseUrl; - showLog(logMsg); + showLog("[Android] 获取到资源地址: " + baseUrl); return baseUrl; } return null; @@ -280,7 +260,7 @@ public class FirstActivity extends BaseActivity { @JavascriptInterface public void callApiWithAddress(String apiPath) { - // 实现保持不变 + // 保持空实现 } @JavascriptInterface @@ -288,9 +268,7 @@ public class FirstActivity extends BaseActivity { FirstActivity activity = activityRef.get(); if (activity != null) { activity.runOnUiThread(() -> { - // 安全转义 - String escapedMessage = message - .replace("\\", "\\\\") + String escapedMessage = message.replace("\\", "\\\\") .replace("'", "\\'") .replace("\"", "\\\"") .replace("\n", "\\n") @@ -307,7 +285,7 @@ public class FirstActivity extends BaseActivity { protected void refresh() { // 空实现 } - +// // private void log(String tag, String message) { // Log.d(tag, message); // if (webViewLogger != null) { @@ -330,4 +308,4 @@ class WebViewLogger { Log.d(tag, message); handler.post(() -> bridge.showLog("[" + tag + "] " + message)); } -} \ No newline at end of file +} From 4964c7e207469b934eb501811a0ff31f629344da Mon Sep 17 00:00:00 2001 From: frank wang <425294756@qq.com> Date: Mon, 13 Oct 2025 19:43:10 +0800 Subject: [PATCH 02/12] =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/pxkj/jwzs/FirstActivity.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/pxkj/jwzs/FirstActivity.java b/app/src/main/java/com/pxkj/jwzs/FirstActivity.java index e1b41e2..3eadfac 100644 --- a/app/src/main/java/com/pxkj/jwzs/FirstActivity.java +++ b/app/src/main/java/com/pxkj/jwzs/FirstActivity.java @@ -207,9 +207,7 @@ public class FirstActivity extends BaseActivity { private boolean isDownloadUrl(String url) { if (TextUtils.isEmpty(url)) return false; - - return true; - + return true; // return url.endsWith(".pdf") // || url.endsWith(".doc") // || url.endsWith(".docx") @@ -263,6 +261,15 @@ public class FirstActivity extends BaseActivity { // 保持空实现 } + // 新增:供前端H5调用下载 + @JavascriptInterface + public void downloadFile(String url) { + FirstActivity activity = activityRef.get(); + if (activity != null && !TextUtils.isEmpty(url)) { + activity.runOnUiThread(() -> activity.downloadFile(url)); + } + } + @JavascriptInterface public void showLog(String message) { FirstActivity activity = activityRef.get(); From e091197527417b38c2104f971add26a669312362 Mon Sep 17 00:00:00 2001 From: frank wang <425294756@qq.com> Date: Tue, 14 Oct 2025 10:18:16 +0800 Subject: [PATCH 03/12] =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/pxkj/jwzs/FirstActivity.java | 75 ++++++++++++++++++- 1 file changed, 71 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/pxkj/jwzs/FirstActivity.java b/app/src/main/java/com/pxkj/jwzs/FirstActivity.java index 3eadfac..2438036 100644 --- a/app/src/main/java/com/pxkj/jwzs/FirstActivity.java +++ b/app/src/main/java/com/pxkj/jwzs/FirstActivity.java @@ -215,10 +215,23 @@ public class FirstActivity extends BaseActivity { // || url.endsWith(".xlsx") // || url.contains("/api/file/"); } + private long currentDownloadId = -1; // 保存当前下载任务ID private void downloadFile(String url) { try { - DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); + if (TextUtils.isEmpty(url)) { + Toast.makeText(this, "下载地址为空", Toast.LENGTH_SHORT).show(); + return; + } + + if (url.startsWith("blob:") || url.startsWith("data:")) { + Toast.makeText(this, "无法直接下载 Blob 文件,请检查前端下载逻辑", Toast.LENGTH_SHORT).show(); + return; + } + + Uri uri = Uri.parse(url); + DownloadManager.Request request = new DownloadManager.Request(uri); + String fileName = URLUtil.guessFileName(url, null, null); request.setTitle(fileName); request.setDescription("正在下载文件..."); @@ -227,10 +240,64 @@ public class FirstActivity extends BaseActivity { request.allowScanningByMediaScanner(); request.addRequestHeader("User-Agent", System.getProperty("http.agent")); - DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); - dm.enqueue(request); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + request.setRequiresCharging(false); + request.setAllowedOverMetered(true); + request.setAllowedOverRoaming(true); + } + + String mimeType = getMimeTypeForUrl(url); + request.setMimeType(!TextUtils.isEmpty(mimeType) ? mimeType : "application/octet-stream"); + + DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); + if (dm != null) { + currentDownloadId = dm.enqueue(request); + Toast.makeText(this, "文件已开始下载,请等待", Toast.LENGTH_SHORT).show(); + + // ✅ 注册广播监听下载完成事件 + registerReceiver(new android.content.BroadcastReceiver() { + @Override + public void onReceive(Context context, android.content.Intent intent) { + long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); + if (id == currentDownloadId) { + DownloadManager.Query query = new DownloadManager.Query(); + query.setFilterById(id); + android.database.Cursor cursor = dm.query(query); + if (cursor != null && cursor.moveToFirst()) { + int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS); + if (DownloadManager.STATUS_SUCCESSFUL == cursor.getInt(columnIndex)) { + String uriString = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)); + if (uriString != null) { + try { + Uri fileUri = Uri.parse(uriString); + String type = getMimeTypeForUrl(fileUri.toString()); + + android.content.Intent openIntent = new android.content.Intent(android.content.Intent.ACTION_VIEW); + openIntent.setFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK | android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION); + openIntent.setDataAndType(fileUri, type); + + // ✅ 检查系统是否有能打开的 App + if (openIntent.resolveActivity(context.getPackageManager()) != null) { + context.startActivity(openIntent); + } else { + Toast.makeText(context, "下载完成,请前往“下载”文件夹手动打开该文件", Toast.LENGTH_LONG).show(); + } + } catch (Exception e) { + Toast.makeText(context, "下载完成,但无法打开文件: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + } + } + cursor.close(); + } + // ✅ 只监听一次下载任务 + unregisterReceiver(this); + } + } + }, new android.content.IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); + } else { + Toast.makeText(this, "系统下载服务不可用", Toast.LENGTH_SHORT).show(); + } - Toast.makeText(this, "文件已开始下载,完成后可在通知栏查看", Toast.LENGTH_SHORT).show(); } catch (Exception e) { e.printStackTrace(); Toast.makeText(this, "下载失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); From 31ffe130296714e617dd82c9bdc0e5b597825a75 Mon Sep 17 00:00:00 2001 From: frank wang <425294756@qq.com> Date: Tue, 14 Oct 2025 19:27:20 +0800 Subject: [PATCH 04/12] =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E8=A1=A5=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/pxkj/jwzs/FirstActivity.java | 107 +++++++++++------- 1 file changed, 66 insertions(+), 41 deletions(-) diff --git a/app/src/main/java/com/pxkj/jwzs/FirstActivity.java b/app/src/main/java/com/pxkj/jwzs/FirstActivity.java index 2438036..3a318e2 100644 --- a/app/src/main/java/com/pxkj/jwzs/FirstActivity.java +++ b/app/src/main/java/com/pxkj/jwzs/FirstActivity.java @@ -34,6 +34,7 @@ public class FirstActivity extends BaseActivity { private static final String TAG = "FirstActivity"; private WebView webView; protected WebViewLogger webViewLogger; + private final Handler handler = new Handler(Looper.getMainLooper()); // 扩展的 MIME 类型映射 private static final Map MIME_TYPES = new HashMap<>(); @@ -52,6 +53,27 @@ public class FirstActivity extends BaseActivity { MIME_TYPES.put("woff2", "font/woff2"); MIME_TYPES.put("ttf", "font/ttf"); MIME_TYPES.put("wasm", "application/wasm"); + + MIME_TYPES.put("pdf", "application/pdf"); + MIME_TYPES.put("zip", "application/zip"); + MIME_TYPES.put("rar", "application/x-rar-compressed"); + MIME_TYPES.put("7z", "application/x-7z-compressed"); + MIME_TYPES.put("csv", "text/csv"); + MIME_TYPES.put("txt", "text/plain"); + MIME_TYPES.put("mp3", "audio/mpeg"); + MIME_TYPES.put("mp4", "video/mp4"); + MIME_TYPES.put("mov", "video/quicktime"); + MIME_TYPES.put("webm", "video/webm"); + MIME_TYPES.put("ogg", "audio/ogg"); + MIME_TYPES.put("wav", "audio/wav"); + MIME_TYPES.put("eot", "application/vnd.ms-fontobject"); + MIME_TYPES.put("otf", "font/otf"); + MIME_TYPES.put("doc", "application/msword"); + MIME_TYPES.put("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"); + MIME_TYPES.put("xls", "application/vnd.ms-excel"); + MIME_TYPES.put("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + MIME_TYPES.put("ppt", "application/vnd.ms-powerpoint"); + MIME_TYPES.put("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"); } @Override @@ -253,47 +275,7 @@ public class FirstActivity extends BaseActivity { if (dm != null) { currentDownloadId = dm.enqueue(request); Toast.makeText(this, "文件已开始下载,请等待", Toast.LENGTH_SHORT).show(); - - // ✅ 注册广播监听下载完成事件 - registerReceiver(new android.content.BroadcastReceiver() { - @Override - public void onReceive(Context context, android.content.Intent intent) { - long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); - if (id == currentDownloadId) { - DownloadManager.Query query = new DownloadManager.Query(); - query.setFilterById(id); - android.database.Cursor cursor = dm.query(query); - if (cursor != null && cursor.moveToFirst()) { - int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS); - if (DownloadManager.STATUS_SUCCESSFUL == cursor.getInt(columnIndex)) { - String uriString = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)); - if (uriString != null) { - try { - Uri fileUri = Uri.parse(uriString); - String type = getMimeTypeForUrl(fileUri.toString()); - - android.content.Intent openIntent = new android.content.Intent(android.content.Intent.ACTION_VIEW); - openIntent.setFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK | android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION); - openIntent.setDataAndType(fileUri, type); - - // ✅ 检查系统是否有能打开的 App - if (openIntent.resolveActivity(context.getPackageManager()) != null) { - context.startActivity(openIntent); - } else { - Toast.makeText(context, "下载完成,请前往“下载”文件夹手动打开该文件", Toast.LENGTH_LONG).show(); - } - } catch (Exception e) { - Toast.makeText(context, "下载完成,但无法打开文件: " + e.getMessage(), Toast.LENGTH_SHORT).show(); - } - } - } - cursor.close(); - } - // ✅ 只监听一次下载任务 - unregisterReceiver(this); - } - } - }, new android.content.IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); + startDownloadProgressMonitor(dm, currentDownloadId); } else { Toast.makeText(this, "系统下载服务不可用", Toast.LENGTH_SHORT).show(); } @@ -304,6 +286,49 @@ public class FirstActivity extends BaseActivity { } } + /** + * ✅ 监控下载进度,每秒回调一次到前端 + */ + private void startDownloadProgressMonitor(DownloadManager dm, long downloadId) { + new Thread(() -> { + DownloadManager.Query query = new DownloadManager.Query(); + query.setFilterById(downloadId); + boolean downloading = true; + + while (downloading) { + try { + Thread.sleep(1000); + android.database.Cursor cursor = dm.query(query); + if (cursor != null && cursor.moveToFirst()) { + int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)); + long total = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)); + long downloaded = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)); + if (status == DownloadManager.STATUS_RUNNING && total > 0) { + int progress = (int) ((downloaded * 100L) / total); + handler.post(() -> sendProgressToJs(progress)); + } else if (status == DownloadManager.STATUS_SUCCESSFUL) { + downloading = false; + handler.post(() -> sendProgressToJs(100)); + } else if (status == DownloadManager.STATUS_FAILED) { + downloading = false; + handler.post(() -> sendProgressToJs(-1)); + } + cursor.close(); + } + } catch (Exception ignored) {} + } + }).start(); + } + + private void sendProgressToJs(int progress) { + try { + if (webView != null) { + String js = String.format("if(window.onDownloadProgress){window.onDownloadProgress(%d);}", progress); + webView.evaluateJavascript(js, null); + } + } catch (Exception ignored) {} + } + public static class JsBridge { private final WeakReference activityRef; From 14f462050cb9afef2ce10363232255b8ea89e4e6 Mon Sep 17 00:00:00 2001 From: frank wang <425294756@qq.com> Date: Wed, 15 Oct 2025 12:07:56 +0800 Subject: [PATCH 05/12] =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/pxkj/jwzs/FirstActivity.java | 64 +++++++++++-------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/com/pxkj/jwzs/FirstActivity.java b/app/src/main/java/com/pxkj/jwzs/FirstActivity.java index 3a318e2..8fc540c 100644 --- a/app/src/main/java/com/pxkj/jwzs/FirstActivity.java +++ b/app/src/main/java/com/pxkj/jwzs/FirstActivity.java @@ -38,6 +38,7 @@ public class FirstActivity extends BaseActivity { // 扩展的 MIME 类型映射 private static final Map MIME_TYPES = new HashMap<>(); + static { MIME_TYPES.put("js", "text/javascript"); MIME_TYPES.put("mjs", "text/javascript"); @@ -237,6 +238,7 @@ public class FirstActivity extends BaseActivity { // || url.endsWith(".xlsx") // || url.contains("/api/file/"); } + private long currentDownloadId = -1; // 保存当前下载任务ID private void downloadFile(String url) { @@ -274,7 +276,7 @@ public class FirstActivity extends BaseActivity { DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); if (dm != null) { currentDownloadId = dm.enqueue(request); - Toast.makeText(this, "文件已开始下载,请等待", Toast.LENGTH_SHORT).show(); + Toast.makeText(this, "文件已开始下载,请等待" + currentDownloadId, Toast.LENGTH_SHORT).show(); startDownloadProgressMonitor(dm, currentDownloadId); } else { Toast.makeText(this, "系统下载服务不可用", Toast.LENGTH_SHORT).show(); @@ -290,34 +292,40 @@ public class FirstActivity extends BaseActivity { * ✅ 监控下载进度,每秒回调一次到前端 */ private void startDownloadProgressMonitor(DownloadManager dm, long downloadId) { - new Thread(() -> { - DownloadManager.Query query = new DownloadManager.Query(); - query.setFilterById(downloadId); - boolean downloading = true; - while (downloading) { - try { - Thread.sleep(1000); - android.database.Cursor cursor = dm.query(query); - if (cursor != null && cursor.moveToFirst()) { - int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)); - long total = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)); - long downloaded = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)); - if (status == DownloadManager.STATUS_RUNNING && total > 0) { - int progress = (int) ((downloaded * 100L) / total); - handler.post(() -> sendProgressToJs(progress)); - } else if (status == DownloadManager.STATUS_SUCCESSFUL) { - downloading = false; - handler.post(() -> sendProgressToJs(100)); - } else if (status == DownloadManager.STATUS_FAILED) { - downloading = false; - handler.post(() -> sendProgressToJs(-1)); - } - cursor.close(); + DownloadManager.Query query = new DownloadManager.Query(); + query.setFilterById(downloadId); + boolean downloading = true; + + while (downloading) { + try { + Thread.sleep(1000); + android.database.Cursor cursor = dm.query(query); + Toast.makeText(this, "文件已开始下载,请等待" + cursor, Toast.LENGTH_SHORT).show(); + if (cursor != null && cursor.moveToFirst()) { + int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)); + long total = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)); + long downloaded = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)); + Toast.makeText(this, "文件已开始下载,请等待" + status + "," + total + "," + downloaded, Toast.LENGTH_SHORT).show(); + if (status == DownloadManager.STATUS_RUNNING && total > 0) { + int progress = (int) ((downloaded * 100L) / total); + Toast.makeText(this, "1.文件已开始下载,部分进度,调用前端js" + status + "," + total + "," + downloaded, Toast.LENGTH_SHORT).show(); + handler.post(() -> sendProgressToJs(progress)); + } else if (status == DownloadManager.STATUS_SUCCESSFUL) { + Toast.makeText(this, "2.文件已开始下载,进度成功,调用前端js" + status + "," + total + "," + downloaded, Toast.LENGTH_SHORT).show(); + downloading = false; + handler.post(() -> sendProgressToJs(100)); + } else if (status == DownloadManager.STATUS_FAILED) { + Toast.makeText(this, "3.文件已开始下载,进度失败,调用前端js" + status + "," + total + "," + downloaded, Toast.LENGTH_SHORT).show(); + downloading = false; + handler.post(() -> sendProgressToJs(-1)); } - } catch (Exception ignored) {} + cursor.close(); + } + } catch (Exception ignored) { + Toast.makeText(this, "文件已开始下载,请等待报错", Toast.LENGTH_SHORT).show(); } - }).start(); + } } private void sendProgressToJs(int progress) { @@ -326,7 +334,9 @@ public class FirstActivity extends BaseActivity { String js = String.format("if(window.onDownloadProgress){window.onDownloadProgress(%d);}", progress); webView.evaluateJavascript(js, null); } - } catch (Exception ignored) {} + } catch (Exception ignored) { + Toast.makeText(this, "文件已开始下载,请等待报错sendProgressToJs", Toast.LENGTH_SHORT).show(); + } } public static class JsBridge { From b27394526cddcc9e0e6c7efeb918d3b77b78ca0b Mon Sep 17 00:00:00 2001 From: frank wang <425294756@qq.com> Date: Wed, 15 Oct 2025 14:56:00 +0800 Subject: [PATCH 06/12] =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/pxkj/jwzs/FirstActivity.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/pxkj/jwzs/FirstActivity.java b/app/src/main/java/com/pxkj/jwzs/FirstActivity.java index 8fc540c..9170eb6 100644 --- a/app/src/main/java/com/pxkj/jwzs/FirstActivity.java +++ b/app/src/main/java/com/pxkj/jwzs/FirstActivity.java @@ -276,7 +276,6 @@ public class FirstActivity extends BaseActivity { DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); if (dm != null) { currentDownloadId = dm.enqueue(request); - Toast.makeText(this, "文件已开始下载,请等待" + currentDownloadId, Toast.LENGTH_SHORT).show(); startDownloadProgressMonitor(dm, currentDownloadId); } else { Toast.makeText(this, "系统下载服务不可用", Toast.LENGTH_SHORT).show(); @@ -299,24 +298,23 @@ public class FirstActivity extends BaseActivity { while (downloading) { try { + Toast.makeText(this, "文件已开始下载,请等待", Toast.LENGTH_SHORT).show(); Thread.sleep(1000); android.database.Cursor cursor = dm.query(query); - Toast.makeText(this, "文件已开始下载,请等待" + cursor, Toast.LENGTH_SHORT).show(); if (cursor != null && cursor.moveToFirst()) { int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)); long total = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)); long downloaded = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)); - Toast.makeText(this, "文件已开始下载,请等待" + status + "," + total + "," + downloaded, Toast.LENGTH_SHORT).show(); if (status == DownloadManager.STATUS_RUNNING && total > 0) { int progress = (int) ((downloaded * 100L) / total); - Toast.makeText(this, "1.文件已开始下载,部分进度,调用前端js" + status + "," + total + "," + downloaded, Toast.LENGTH_SHORT).show(); + Toast.makeText(this, "下载中,当前进度为" + progress + "%", Toast.LENGTH_SHORT).show(); handler.post(() -> sendProgressToJs(progress)); } else if (status == DownloadManager.STATUS_SUCCESSFUL) { - Toast.makeText(this, "2.文件已开始下载,进度成功,调用前端js" + status + "," + total + "," + downloaded, Toast.LENGTH_SHORT).show(); + Toast.makeText(this, "下载完成,请到文件管理查看", Toast.LENGTH_SHORT).show(); downloading = false; handler.post(() -> sendProgressToJs(100)); } else if (status == DownloadManager.STATUS_FAILED) { - Toast.makeText(this, "3.文件已开始下载,进度失败,调用前端js" + status + "," + total + "," + downloaded, Toast.LENGTH_SHORT).show(); + Toast.makeText(this, "下载失败" + status + "," + total + "," + downloaded, Toast.LENGTH_SHORT).show(); downloading = false; handler.post(() -> sendProgressToJs(-1)); } From d1deee482caa5bbcc1e3952d1d6bd198165eda7d Mon Sep 17 00:00:00 2001 From: frank wang <425294756@qq.com> Date: Wed, 15 Oct 2025 16:33:58 +0800 Subject: [PATCH 07/12] =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/pxkj/jwzs/FirstActivity.java | 80 ++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/pxkj/jwzs/FirstActivity.java b/app/src/main/java/com/pxkj/jwzs/FirstActivity.java index 9170eb6..12b1cb2 100644 --- a/app/src/main/java/com/pxkj/jwzs/FirstActivity.java +++ b/app/src/main/java/com/pxkj/jwzs/FirstActivity.java @@ -24,6 +24,11 @@ import android.widget.Toast; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; +import android.app.Activity; +import android.content.Intent; // ← 文件选择核心类 +import android.database.Cursor; // ← 解析文件信息 +import android.provider.OpenableColumns; // ← 获取文件名、大小 + import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; @@ -275,6 +280,7 @@ public class FirstActivity extends BaseActivity { DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); if (dm != null) { + Toast.makeText(this, "文件已开始下载,请等待", Toast.LENGTH_SHORT).show(); currentDownloadId = dm.enqueue(request); startDownloadProgressMonitor(dm, currentDownloadId); } else { @@ -298,7 +304,6 @@ public class FirstActivity extends BaseActivity { while (downloading) { try { - Toast.makeText(this, "文件已开始下载,请等待", Toast.LENGTH_SHORT).show(); Thread.sleep(1000); android.database.Cursor cursor = dm.query(query); if (cursor != null && cursor.moveToFirst()) { @@ -337,6 +342,71 @@ public class FirstActivity extends BaseActivity { } } + // 在 FirstActivity.java 中添加以下代码 + + private static final int REQUEST_CODE_FILE_PICK = 2001; + private Uri selectedFileUri; + + private void chooseFile() { + runOnUiThread(() -> { + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.setType("*/*"); // 所有类型 + intent.addCategory(Intent.CATEGORY_OPENABLE); + startActivityForResult(Intent.createChooser(intent, "请选择文件"), REQUEST_CODE_FILE_PICK); + }); + } + + /** + * 选择文件后的回调 + */ + @Override + protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == REQUEST_CODE_FILE_PICK && resultCode == RESULT_OK && data != null) { + selectedFileUri = data.getData(); + if (selectedFileUri != null) { + String fileName = getFileNameFromUri(selectedFileUri); + String filePath = selectedFileUri.toString(); + + // 将选择的文件信息传回前端 JS + if (webView != null) { + String jsCode = String.format( + "if(window.onFileChosen){window.onFileChosen('%s','%s');}", + fileName.replace("'", "\\'"), + filePath.replace("'", "\\'") + ); + webView.evaluateJavascript(jsCode, null); + } + + Toast.makeText(this, "已选择文件: " + fileName, Toast.LENGTH_SHORT).show(); + } + } + } + + /** + * 从 Uri 中获取文件名 + */ + private String getFileNameFromUri(Uri uri) { + String result = null; + if ("content".equals(uri.getScheme())) { + try (android.database.Cursor cursor = getContentResolver().query(uri, null, null, null, null)) { + if (cursor != null && cursor.moveToFirst()) { + result = cursor.getString(cursor.getColumnIndex(android.provider.OpenableColumns.DISPLAY_NAME)); + } + } + } + if (result == null) { + result = uri.getPath(); + int cut = result.lastIndexOf('/'); + if (cut != -1) { + result = result.substring(cut + 1); + } + } + return result; + } + + + public static class JsBridge { private final WeakReference activityRef; @@ -369,6 +439,14 @@ public class FirstActivity extends BaseActivity { activity.runOnUiThread(() -> activity.downloadFile(url)); } } + // ✅ 供前端调用的文件选择方法 + @JavascriptInterface + public void chooseFile() { + FirstActivity activity = activityRef.get(); + if (activity != null) { + activity.runOnUiThread(activity::chooseFile); + } + } @JavascriptInterface public void showLog(String message) { From b5e81153659e70ab91dad7b0318444401eb59a8f Mon Sep 17 00:00:00 2001 From: frank wang <425294756@qq.com> Date: Thu, 30 Oct 2025 13:53:15 +0800 Subject: [PATCH 08/12] =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/pxkj/jwzs/FirstActivity.java | 188 +++++++++++++++--- 1 file changed, 155 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/com/pxkj/jwzs/FirstActivity.java b/app/src/main/java/com/pxkj/jwzs/FirstActivity.java index 12b1cb2..391c03d 100644 --- a/app/src/main/java/com/pxkj/jwzs/FirstActivity.java +++ b/app/src/main/java/com/pxkj/jwzs/FirstActivity.java @@ -29,6 +29,8 @@ import android.content.Intent; // ← 文件选择核心类 import android.database.Cursor; // ← 解析文件信息 import android.provider.OpenableColumns; // ← 获取文件名、大小 +import org.json.JSONObject; + import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; @@ -244,6 +246,19 @@ public class FirstActivity extends BaseActivity { // || url.contains("/api/file/"); } + private void previewFile(String url) { + try { + if (webView != null) { + webView.loadUrl(url); + } + + Toast.makeText(this, "正在打开文件预览...", Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(this, "预览文件失败: " + e.getMessage(), Toast.LENGTH_LONG).show(); + } + } + private long currentDownloadId = -1; // 保存当前下载任务ID private void downloadFile(String url) { @@ -342,69 +357,158 @@ public class FirstActivity extends BaseActivity { } } - // 在 FirstActivity.java 中添加以下代码 +// ============================== +// 文件选择与上传逻辑(新增部分) +// ============================== - private static final int REQUEST_CODE_FILE_PICK = 2001; - private Uri selectedFileUri; + private static final int REQUEST_CODE_FILE_CHOOSER = 2001; - private void chooseFile() { - runOnUiThread(() -> { - Intent intent = new Intent(Intent.ACTION_GET_CONTENT); - intent.setType("*/*"); // 所有类型 - intent.addCategory(Intent.CATEGORY_OPENABLE); - startActivityForResult(Intent.createChooser(intent, "请选择文件"), REQUEST_CODE_FILE_PICK); - }); + /** + * JS 调用此方法选择文件 + */ + @JavascriptInterface + public void chooseFile() { + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.setType("*/*"); + intent.addCategory(Intent.CATEGORY_OPENABLE); + startActivityForResult(Intent.createChooser(intent, "选择要上传的文件"), REQUEST_CODE_FILE_CHOOSER); } /** - * 选择文件后的回调 + * 文件选择结果回调 */ @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); - if (requestCode == REQUEST_CODE_FILE_PICK && resultCode == RESULT_OK && data != null) { - selectedFileUri = data.getData(); - if (selectedFileUri != null) { - String fileName = getFileNameFromUri(selectedFileUri); - String filePath = selectedFileUri.toString(); - - // 将选择的文件信息传回前端 JS - if (webView != null) { - String jsCode = String.format( - "if(window.onFileChosen){window.onFileChosen('%s','%s');}", - fileName.replace("'", "\\'"), - filePath.replace("'", "\\'") - ); - webView.evaluateJavascript(jsCode, null); - } - - Toast.makeText(this, "已选择文件: " + fileName, Toast.LENGTH_SHORT).show(); + if (requestCode == REQUEST_CODE_FILE_CHOOSER && resultCode == RESULT_OK && data != null) { + Uri uri = data.getData(); + if (uri != null) { + Toast.makeText(this, "文件已选择,开始上传...", Toast.LENGTH_SHORT).show(); + uploadFile(uri); // 自动上传文件 } } } /** - * 从 Uri 中获取文件名 + * 上传文件到服务器 + */ + private void uploadFile(Uri uri) { + new Thread(() -> { + try { + // ✅ 修改为你的文件上传接口地址 +// String uploadUrl = "http://218.92.207.242:9678/file/upload"; // TODO: 替换为后端真实接口 + + String uploadUrl = "http://20.47.196.98:40080/fwzx/v1.0.0/getServiceInfoByServiceId/32092423SJNB12202507111046530001/320924230000-3-0800-5CDEC9969D674E1CBB7E2F86A697B0D7/api/file/upload"; + + String token = getToken(); // ✅ 从本地获取前端传来的 token + if (TextUtils.isEmpty(token)) { + runOnUiThread(() -> Toast.makeText(this, "请先登录后再上传", Toast.LENGTH_SHORT).show()); + return; + } + + // 获取文件名 + String fileName = getFileNameFromUri(uri); + if (TextUtils.isEmpty(fileName)) fileName = "upload_file"; + + // 读取文件内容 + InputStream inputStream = getContentResolver().openInputStream(uri); + byte[] fileBytes = new byte[inputStream.available()]; + inputStream.read(fileBytes); + inputStream.close(); + + // 使用 OkHttp 上传 + okhttp3.OkHttpClient client = new okhttp3.OkHttpClient(); + okhttp3.RequestBody fileBody = okhttp3.RequestBody.create( + okhttp3.MediaType.parse("application/octet-stream"), + fileBytes + ); + okhttp3.MultipartBody requestBody = new okhttp3.MultipartBody.Builder() + .setType(okhttp3.MultipartBody.FORM) + .addFormDataPart("file", fileName, fileBody) + .build(); + + okhttp3.Request request = new okhttp3.Request.Builder() + .url(uploadUrl) + .addHeader("accesstoken", token) // ✅ 添加 token 认证头 + .post(requestBody) + .build(); + + okhttp3.Response response = client.newCall(request).execute(); + + if (response.isSuccessful()) { + String result = response.body().string(); + Log.d(TAG, "文件上传成功: " + result); + + // ✅ 提取 fileName 与后端返回的 data + String safeResult = result.replace("'", "\\'"); // 避免 JS 语法错误 + String safeFileName = fileName.replace("'", "\\'"); + + runOnUiThread(() -> { + Toast.makeText(this, "上传成功", Toast.LENGTH_SHORT).show(); + + if (webView != null) { + // ✅ 传 fileName 与 data 到前端 + String jsCode = String.format( + "window.onFileUploadSuccess && window.onFileUploadSuccess({fileName: '%s', data: %s})", + safeFileName, safeResult + ); + webView.evaluateJavascript(jsCode, null); + } + }); + } else { + runOnUiThread(() -> + Toast.makeText(this, "上传失败: " + response.code(), Toast.LENGTH_LONG).show() + ); + } + + } catch (Exception e) { + e.printStackTrace(); + runOnUiThread(() -> + Toast.makeText(this, "上传异常: " + e.getMessage(), Toast.LENGTH_LONG).show() + ); + } + }).start(); + } + + /** + * 从 Uri 获取文件名 */ private String getFileNameFromUri(Uri uri) { String result = null; if ("content".equals(uri.getScheme())) { try (android.database.Cursor cursor = getContentResolver().query(uri, null, null, null, null)) { if (cursor != null && cursor.moveToFirst()) { - result = cursor.getString(cursor.getColumnIndex(android.provider.OpenableColumns.DISPLAY_NAME)); + result = cursor.getString(cursor.getColumnIndexOrThrow(android.provider.OpenableColumns.DISPLAY_NAME)); } } } if (result == null) { result = uri.getPath(); int cut = result.lastIndexOf('/'); - if (cut != -1) { - result = result.substring(cut + 1); - } + if (cut != -1) result = result.substring(cut + 1); } return result; } +// ============================== +// ✅ 新增:存储与获取 token 的方法 +// ============================== + + private static final String KEY_TOKEN = "USER_TOKEN"; + + // JS 传入 token + @JavascriptInterface + public void setToken(String token) { + if (!TextUtils.isEmpty(token)) { + SpUtils.putString(this, KEY_TOKEN, token); + Log.d(TAG, "已保存 token: " + token); + } + } + + // 获取本地 token + private String getToken() { + return SpUtils.getString(this, KEY_TOKEN, ""); + } public static class JsBridge { @@ -439,6 +543,7 @@ public class FirstActivity extends BaseActivity { activity.runOnUiThread(() -> activity.downloadFile(url)); } } + // ✅ 供前端调用的文件选择方法 @JavascriptInterface public void chooseFile() { @@ -448,6 +553,23 @@ public class FirstActivity extends BaseActivity { } } + // ✅ 供前端调用的文件选择方法 + @JavascriptInterface + public void previewFile(String url) { + FirstActivity activity = activityRef.get(); + if (activity != null && !TextUtils.isEmpty(url)) { + activity.runOnUiThread(() -> activity.previewFile(url)); + } + } + + // ✅ 供前端调用的文件选择方法 + @JavascriptInterface + public void setToken(String token) { + FirstActivity activity = activityRef.get(); + if (activity != null && !TextUtils.isEmpty(token)) { + activity.runOnUiThread(() -> activity.setToken(token)); + } + } @JavascriptInterface public void showLog(String message) { FirstActivity activity = activityRef.get(); From f586a6d0e33f4013c15c7e50b9d10c32dfa8bbe5 Mon Sep 17 00:00:00 2001 From: frank wang <425294756@qq.com> Date: Thu, 30 Oct 2025 16:02:06 +0800 Subject: [PATCH 09/12] =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e56234b..41a7943 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,9 +2,20 @@ + - + + + + + + + + + + + - + + android:value="${APPID}" /> + android:value="${REGIONALISMCODE}" /> + android:value="${NETWORKAREACODE}" /> - + - + - - - - - - \ No newline at end of file + From f8adef2a9e6b08f9f2cc7443ed28c84cd0338903 Mon Sep 17 00:00:00 2001 From: frank wang <425294756@qq.com> Date: Thu, 30 Oct 2025 16:58:16 +0800 Subject: [PATCH 10/12] =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/pxkj/jwzs/FirstActivity.java | 98 +++++++++---------- 1 file changed, 46 insertions(+), 52 deletions(-) diff --git a/app/src/main/java/com/pxkj/jwzs/FirstActivity.java b/app/src/main/java/com/pxkj/jwzs/FirstActivity.java index 391c03d..cc87306 100644 --- a/app/src/main/java/com/pxkj/jwzs/FirstActivity.java +++ b/app/src/main/java/com/pxkj/jwzs/FirstActivity.java @@ -262,50 +262,52 @@ public class FirstActivity extends BaseActivity { private long currentDownloadId = -1; // 保存当前下载任务ID private void downloadFile(String url) { - try { - if (TextUtils.isEmpty(url)) { - Toast.makeText(this, "下载地址为空", Toast.LENGTH_SHORT).show(); - return; + new Thread(() -> { + try { + if (TextUtils.isEmpty(url)) { + Toast.makeText(this, "下载地址为空", Toast.LENGTH_SHORT).show(); + return; + } + + if (url.startsWith("blob:") || url.startsWith("data:")) { + Toast.makeText(this, "无法直接下载 Blob 文件,请检查前端下载逻辑", Toast.LENGTH_SHORT).show(); + return; + } + + Uri uri = Uri.parse(url); + DownloadManager.Request request = new DownloadManager.Request(uri); + + String fileName = URLUtil.guessFileName(url, null, null); + request.setTitle(fileName); + request.setDescription("正在下载文件..."); + request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); + request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName); + request.allowScanningByMediaScanner(); + request.addRequestHeader("User-Agent", System.getProperty("http.agent")); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + request.setRequiresCharging(false); + request.setAllowedOverMetered(true); + request.setAllowedOverRoaming(true); + } + + String mimeType = getMimeTypeForUrl(url); + request.setMimeType(!TextUtils.isEmpty(mimeType) ? mimeType : "application/octet-stream"); + + DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); + if (dm != null) { + Toast.makeText(this, "文件已开始下载,请等待", Toast.LENGTH_SHORT).show(); + currentDownloadId = dm.enqueue(request); + startDownloadProgressMonitor(dm, currentDownloadId); + } else { + Toast.makeText(this, "系统下载服务不可用", Toast.LENGTH_SHORT).show(); + } + + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(this, "下载失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); } - - if (url.startsWith("blob:") || url.startsWith("data:")) { - Toast.makeText(this, "无法直接下载 Blob 文件,请检查前端下载逻辑", Toast.LENGTH_SHORT).show(); - return; - } - - Uri uri = Uri.parse(url); - DownloadManager.Request request = new DownloadManager.Request(uri); - - String fileName = URLUtil.guessFileName(url, null, null); - request.setTitle(fileName); - request.setDescription("正在下载文件..."); - request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); - request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName); - request.allowScanningByMediaScanner(); - request.addRequestHeader("User-Agent", System.getProperty("http.agent")); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - request.setRequiresCharging(false); - request.setAllowedOverMetered(true); - request.setAllowedOverRoaming(true); - } - - String mimeType = getMimeTypeForUrl(url); - request.setMimeType(!TextUtils.isEmpty(mimeType) ? mimeType : "application/octet-stream"); - - DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); - if (dm != null) { - Toast.makeText(this, "文件已开始下载,请等待", Toast.LENGTH_SHORT).show(); - currentDownloadId = dm.enqueue(request); - startDownloadProgressMonitor(dm, currentDownloadId); - } else { - Toast.makeText(this, "系统下载服务不可用", Toast.LENGTH_SHORT).show(); - } - - } catch (Exception e) { - e.printStackTrace(); - Toast.makeText(this, "下载失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); - } + }).start(); } /** @@ -553,15 +555,6 @@ public class FirstActivity extends BaseActivity { } } - // ✅ 供前端调用的文件选择方法 - @JavascriptInterface - public void previewFile(String url) { - FirstActivity activity = activityRef.get(); - if (activity != null && !TextUtils.isEmpty(url)) { - activity.runOnUiThread(() -> activity.previewFile(url)); - } - } - // ✅ 供前端调用的文件选择方法 @JavascriptInterface public void setToken(String token) { @@ -570,6 +563,7 @@ public class FirstActivity extends BaseActivity { activity.runOnUiThread(() -> activity.setToken(token)); } } + @JavascriptInterface public void showLog(String message) { FirstActivity activity = activityRef.get(); From bc79e4176c1e9ecd3a6b5d5c3b010cfd0676ba56 Mon Sep 17 00:00:00 2001 From: frank wang <425294756@qq.com> Date: Thu, 30 Oct 2025 17:52:07 +0800 Subject: [PATCH 11/12] =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E7=9A=84=E9=80=BB=E8=BE=91001?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/pxkj/jwzs/FirstActivity.java | 132 +++++++++++------- 1 file changed, 82 insertions(+), 50 deletions(-) diff --git a/app/src/main/java/com/pxkj/jwzs/FirstActivity.java b/app/src/main/java/com/pxkj/jwzs/FirstActivity.java index cc87306..f5209e1 100644 --- a/app/src/main/java/com/pxkj/jwzs/FirstActivity.java +++ b/app/src/main/java/com/pxkj/jwzs/FirstActivity.java @@ -260,17 +260,23 @@ public class FirstActivity extends BaseActivity { } private long currentDownloadId = -1; // 保存当前下载任务ID - + /** + * ✅ 下载文件并调用系统 DownloadManager + */ private void downloadFile(String url) { new Thread(() -> { try { if (TextUtils.isEmpty(url)) { - Toast.makeText(this, "下载地址为空", Toast.LENGTH_SHORT).show(); + handler.post(() -> + Toast.makeText(this, "下载地址为空", Toast.LENGTH_SHORT).show() + ); return; } if (url.startsWith("blob:") || url.startsWith("data:")) { - Toast.makeText(this, "无法直接下载 Blob 文件,请检查前端下载逻辑", Toast.LENGTH_SHORT).show(); + handler.post(() -> + Toast.makeText(this, "无法直接下载 Blob 文件,请检查前端下载逻辑", Toast.LENGTH_SHORT).show() + ); return; } @@ -296,16 +302,22 @@ public class FirstActivity extends BaseActivity { DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); if (dm != null) { - Toast.makeText(this, "文件已开始下载,请等待", Toast.LENGTH_SHORT).show(); + handler.post(() -> + Toast.makeText(this, "文件已开始下载,请等待", Toast.LENGTH_SHORT).show() + ); currentDownloadId = dm.enqueue(request); startDownloadProgressMonitor(dm, currentDownloadId); } else { - Toast.makeText(this, "系统下载服务不可用", Toast.LENGTH_SHORT).show(); + handler.post(() -> + Toast.makeText(this, "系统下载服务不可用", Toast.LENGTH_SHORT).show() + ); } } catch (Exception e) { e.printStackTrace(); - Toast.makeText(this, "下载失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + handler.post(() -> + Toast.makeText(this, "下载失败: " + e.getMessage(), Toast.LENGTH_SHORT).show() + ); } }).start(); } @@ -314,48 +326,69 @@ public class FirstActivity extends BaseActivity { * ✅ 监控下载进度,每秒回调一次到前端 */ private void startDownloadProgressMonitor(DownloadManager dm, long downloadId) { + new Thread(() -> { + DownloadManager.Query query = new DownloadManager.Query(); + query.setFilterById(downloadId); + boolean downloading = true; - DownloadManager.Query query = new DownloadManager.Query(); - query.setFilterById(downloadId); - boolean downloading = true; + while (downloading) { + try { + Thread.sleep(1000); + android.database.Cursor cursor = dm.query(query); + if (cursor != null && cursor.moveToFirst()) { + int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)); + long total = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)); + long downloaded = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)); - while (downloading) { - try { - Thread.sleep(1000); - android.database.Cursor cursor = dm.query(query); - if (cursor != null && cursor.moveToFirst()) { - int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)); - long total = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)); - long downloaded = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)); - if (status == DownloadManager.STATUS_RUNNING && total > 0) { - int progress = (int) ((downloaded * 100L) / total); - Toast.makeText(this, "下载中,当前进度为" + progress + "%", Toast.LENGTH_SHORT).show(); - handler.post(() -> sendProgressToJs(progress)); - } else if (status == DownloadManager.STATUS_SUCCESSFUL) { - Toast.makeText(this, "下载完成,请到文件管理查看", Toast.LENGTH_SHORT).show(); - downloading = false; - handler.post(() -> sendProgressToJs(100)); - } else if (status == DownloadManager.STATUS_FAILED) { - Toast.makeText(this, "下载失败" + status + "," + total + "," + downloaded, Toast.LENGTH_SHORT).show(); - downloading = false; - handler.post(() -> sendProgressToJs(-1)); + if (status == DownloadManager.STATUS_RUNNING && total > 0) { + int progress = (int) ((downloaded * 100L) / total); + handler.post(() -> { + sendProgressToJs(progress); + // 可选:减少 toast 频率,比如每 20% 提示一次 + if (progress % 20 == 0) { + Toast.makeText(this, "下载中:" + progress + "%", Toast.LENGTH_SHORT).show(); + } + }); + } else if (status == DownloadManager.STATUS_SUCCESSFUL) { + downloading = false; + handler.post(() -> { + sendProgressToJs(100); + Toast.makeText(this, "下载完成,请到文件管理查看", Toast.LENGTH_SHORT).show(); + }); + } else if (status == DownloadManager.STATUS_FAILED) { + downloading = false; + handler.post(() -> { + sendProgressToJs(-1); + Toast.makeText(this, "下载失败", Toast.LENGTH_SHORT).show(); + }); + } + cursor.close(); } - cursor.close(); + } catch (Exception e) { + e.printStackTrace(); + downloading = false; + handler.post(() -> + Toast.makeText(this, "监控异常:" + e.getMessage(), Toast.LENGTH_SHORT).show() + ); } - } catch (Exception ignored) { - Toast.makeText(this, "文件已开始下载,请等待报错", Toast.LENGTH_SHORT).show(); } - } + }).start(); } + /** + * ✅ 向前端回调进度 + */ private void sendProgressToJs(int progress) { try { if (webView != null) { String js = String.format("if(window.onDownloadProgress){window.onDownloadProgress(%d);}", progress); webView.evaluateJavascript(js, null); } - } catch (Exception ignored) { - Toast.makeText(this, "文件已开始下载,请等待报错sendProgressToJs", Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + e.printStackTrace(); + handler.post(() -> + Toast.makeText(this, "进度回调异常:" + e.getMessage(), Toast.LENGTH_SHORT).show() + ); } } @@ -390,35 +423,34 @@ public class FirstActivity extends BaseActivity { } } } - /** - * 上传文件到服务器 + * ✅ 上传文件,并在上传成功后将 fileName、data、fileSize 传给前端 */ private void uploadFile(Uri uri) { new Thread(() -> { try { - // ✅ 修改为你的文件上传接口地址 -// String uploadUrl = "http://218.92.207.242:9678/file/upload"; // TODO: 替换为后端真实接口 - + // ✅ 上传接口 String uploadUrl = "http://20.47.196.98:40080/fwzx/v1.0.0/getServiceInfoByServiceId/32092423SJNB12202507111046530001/320924230000-3-0800-5CDEC9969D674E1CBB7E2F86A697B0D7/api/file/upload"; - String token = getToken(); // ✅ 从本地获取前端传来的 token + String token = getToken(); if (TextUtils.isEmpty(token)) { runOnUiThread(() -> Toast.makeText(this, "请先登录后再上传", Toast.LENGTH_SHORT).show()); return; } - // 获取文件名 + // ✅ 获取文件名 String fileName = getFileNameFromUri(uri); if (TextUtils.isEmpty(fileName)) fileName = "upload_file"; - // 读取文件内容 + // ✅ 读取文件内容并计算文件大小 InputStream inputStream = getContentResolver().openInputStream(uri); byte[] fileBytes = new byte[inputStream.available()]; inputStream.read(fileBytes); inputStream.close(); - // 使用 OkHttp 上传 + long fileSize = fileBytes.length; // 文件大小(字节) + + // ✅ 构建 OkHttp 上传请求 okhttp3.OkHttpClient client = new okhttp3.OkHttpClient(); okhttp3.RequestBody fileBody = okhttp3.RequestBody.create( okhttp3.MediaType.parse("application/octet-stream"), @@ -431,7 +463,7 @@ public class FirstActivity extends BaseActivity { okhttp3.Request request = new okhttp3.Request.Builder() .url(uploadUrl) - .addHeader("accesstoken", token) // ✅ 添加 token 认证头 + .addHeader("accesstoken", token) // ✅ 加 token .post(requestBody) .build(); @@ -441,18 +473,17 @@ public class FirstActivity extends BaseActivity { String result = response.body().string(); Log.d(TAG, "文件上传成功: " + result); - // ✅ 提取 fileName 与后端返回的 data - String safeResult = result.replace("'", "\\'"); // 避免 JS 语法错误 + String safeResult = result.replace("'", "\\'"); String safeFileName = fileName.replace("'", "\\'"); + // ✅ JS 回调:fileName、data、fileSize runOnUiThread(() -> { Toast.makeText(this, "上传成功", Toast.LENGTH_SHORT).show(); if (webView != null) { - // ✅ 传 fileName 与 data 到前端 String jsCode = String.format( - "window.onFileUploadSuccess && window.onFileUploadSuccess({fileName: '%s', data: %s})", - safeFileName, safeResult + "window.onFileUploadSuccess && window.onFileUploadSuccess({fileName: '%s', data: %s, fileSize: %.2f})", + safeFileName, safeResult, fileSize ); webView.evaluateJavascript(jsCode, null); } @@ -472,6 +503,7 @@ public class FirstActivity extends BaseActivity { }).start(); } + /** * 从 Uri 获取文件名 */ From 569c02516901345de71a144e1da65e5ebe8bbb9e Mon Sep 17 00:00:00 2001 From: frank wang <425294756@qq.com> Date: Thu, 30 Oct 2025 18:00:29 +0800 Subject: [PATCH 12/12] =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E7=9A=84=E9=80=BB=E8=BE=91002?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/pxkj/jwzs/FirstActivity.java | 84 ++++++++++++------- 1 file changed, 54 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/com/pxkj/jwzs/FirstActivity.java b/app/src/main/java/com/pxkj/jwzs/FirstActivity.java index f5209e1..c101e6d 100644 --- a/app/src/main/java/com/pxkj/jwzs/FirstActivity.java +++ b/app/src/main/java/com/pxkj/jwzs/FirstActivity.java @@ -246,19 +246,6 @@ public class FirstActivity extends BaseActivity { // || url.contains("/api/file/"); } - private void previewFile(String url) { - try { - if (webView != null) { - webView.loadUrl(url); - } - - Toast.makeText(this, "正在打开文件预览...", Toast.LENGTH_SHORT).show(); - } catch (Exception e) { - e.printStackTrace(); - Toast.makeText(this, "预览文件失败: " + e.getMessage(), Toast.LENGTH_LONG).show(); - } - } - private long currentDownloadId = -1; // 保存当前下载任务ID /** * ✅ 下载文件并调用系统 DownloadManager @@ -429,7 +416,7 @@ public class FirstActivity extends BaseActivity { private void uploadFile(Uri uri) { new Thread(() -> { try { - // ✅ 上传接口 + // ✅ 上传接口地址 String uploadUrl = "http://20.47.196.98:40080/fwzx/v1.0.0/getServiceInfoByServiceId/32092423SJNB12202507111046530001/320924230000-3-0800-5CDEC9969D674E1CBB7E2F86A697B0D7/api/file/upload"; String token = getToken(); @@ -438,32 +425,40 @@ public class FirstActivity extends BaseActivity { return; } - // ✅ 获取文件名 + // ✅ 获取文件名和大小 String fileName = getFileNameFromUri(uri); if (TextUtils.isEmpty(fileName)) fileName = "upload_file"; + long fileSize = getFileSizeFromUri(uri); - // ✅ 读取文件内容并计算文件大小 + // ✅ 使用流式读取方式构建 RequestBody(防止 OOM) InputStream inputStream = getContentResolver().openInputStream(uri); - byte[] fileBytes = new byte[inputStream.available()]; - inputStream.read(fileBytes); - inputStream.close(); + okhttp3.RequestBody fileBody = new okhttp3.RequestBody() { + @Nullable + @Override + public okhttp3.MediaType contentType() { + return okhttp3.MediaType.parse("application/octet-stream"); + } - long fileSize = fileBytes.length; // 文件大小(字节) + @Override + public void writeTo(okio.BufferedSink sink) throws IOException { + byte[] buffer = new byte[4096]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + sink.write(buffer, 0, bytesRead); + } + inputStream.close(); + } + }; - // ✅ 构建 OkHttp 上传请求 - okhttp3.OkHttpClient client = new okhttp3.OkHttpClient(); - okhttp3.RequestBody fileBody = okhttp3.RequestBody.create( - okhttp3.MediaType.parse("application/octet-stream"), - fileBytes - ); okhttp3.MultipartBody requestBody = new okhttp3.MultipartBody.Builder() .setType(okhttp3.MultipartBody.FORM) .addFormDataPart("file", fileName, fileBody) .build(); + okhttp3.OkHttpClient client = new okhttp3.OkHttpClient(); okhttp3.Request request = new okhttp3.Request.Builder() .url(uploadUrl) - .addHeader("accesstoken", token) // ✅ 加 token + .addHeader("accesstoken", token) // ✅ 带 token .post(requestBody) .build(); @@ -476,13 +471,12 @@ public class FirstActivity extends BaseActivity { String safeResult = result.replace("'", "\\'"); String safeFileName = fileName.replace("'", "\\'"); - // ✅ JS 回调:fileName、data、fileSize + // ✅ JS 回调 fileName、data、fileSize runOnUiThread(() -> { Toast.makeText(this, "上传成功", Toast.LENGTH_SHORT).show(); - if (webView != null) { String jsCode = String.format( - "window.onFileUploadSuccess && window.onFileUploadSuccess({fileName: '%s', data: %s, fileSize: %.2f})", + "window.onFileUploadSuccess && window.onFileUploadSuccess({fileName: '%s', data: %s, fileSize: %d})", safeFileName, safeResult, fileSize ); webView.evaluateJavascript(jsCode, null); @@ -503,6 +497,36 @@ public class FirstActivity extends BaseActivity { }).start(); } + /** + * ✅ 获取文件大小(兼容 content:// 与 file://) + */ + private long getFileSizeFromUri(Uri uri) { + long fileSize = 0L; + if ("content".equals(uri.getScheme())) { + try (Cursor cursor = getContentResolver().query(uri, null, null, null, null)) { + if (cursor != null && cursor.moveToFirst()) { + int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE); + if (sizeIndex != -1) { + fileSize = cursor.getLong(sizeIndex); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + if (fileSize <= 0) { + // 尝试从 File 读取 + String path = uri.getPath(); + if (path != null) { + java.io.File file = new java.io.File(path); + if (file.exists()) { + fileSize = file.length(); + } + } + } + return fileSize; + } + /** * 从 Uri 获取文件名