soul-browser/sources/java/com/mycompany/app/web/JsonViewHelper.java
KaKi87 8920200aba
Add Firefox's JSON Viewer (#56)
* Replace Chromium's plain JSON view with Mozilla's JSON Viewer.

Bundle the pd4d10 Firefox JSON Viewer port and inject it on pages that
show JSON as a bare <pre>, matching the desktop extension behavior.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Reference the Mozilla JSON viewer commit in the README.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Add a mobile viewport meta tag to the Mozilla JSON viewer.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Update README

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-16 21:20:51 +02:00

89 lines
2.7 KiB
Java

package com.mycompany.app.web;
import android.content.Context;
import android.text.TextUtils;
import android.webkit.ValueCallback;
import android.webkit.WebView;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
/**
* Replaces Chromium's plain JSON &lt;pre&gt; view with Mozilla Firefox's JSON Viewer
* (via the pd4d10/json-viewer port bundled under assets/jsonview/).
*/
public final class JsonViewHelper {
private static final String DETECT_JS =
"(function(){if(window.__soulMozillaJsonView)return false;"
+ "var el=document.body&&document.body.firstElementChild;"
+ "if(!(el instanceof HTMLElement)||el.tagName!=='PRE')return false;"
+ "try{JSON.parse(el.innerText);return true;}catch(e){return false;}})();";
private static String cachedViewerJs;
private JsonViewHelper() {
}
public static void inject(WebView webView) {
if (webView == null) {
return;
}
final WebView target = webView;
try {
target.evaluateJavascript(DETECT_JS, new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
if (value != null && value.contains("true")) {
injectViewer(target);
}
}
});
} catch (Exception ignored) {
}
}
private static void injectViewer(WebView webView) {
if (webView == null) {
return;
}
Context context = webView.getContext();
if (context == null) {
return;
}
String js = loadViewerJs(context);
if (TextUtils.isEmpty(js)) {
return;
}
try {
webView.evaluateJavascript(js, null);
} catch (Exception ignored) {
}
}
private static synchronized String loadViewerJs(Context context) {
if (cachedViewerJs != null) {
return cachedViewerJs;
}
InputStream in = null;
try {
in = context.getAssets().open("jsonview/viewer.js");
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[8192];
int n;
while ((n = in.read(buf)) >= 0) {
out.write(buf, 0, n);
}
cachedViewerJs = new String(out.toByteArray(), StandardCharsets.UTF_8);
} catch (Exception e) {
cachedViewerJs = "";
} finally {
if (in != null) {
try {
in.close();
} catch (Exception ignored) {
}
}
}
return cachedViewerJs;
}
}