Skip to content

Commit 55f0f1b

Browse files
authored
Merge pull request #733 from quoid/refactor/app-webview-initialization
refactor: improve app webview initialization process
2 parents 2700906 + 4e1f5fb commit 55f0f1b

File tree

3 files changed

+102
-75
lines changed

3 files changed

+102
-75
lines changed

src/app/App.svelte

Lines changed: 60 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3,70 +3,80 @@
33
import logo from "./img/logo.svg?raw";
44
55
const baseUrl = "https://github.com/quoid/userscripts";
6+
const webkit = window.webkit.messageHandlers.controller;
67
7-
let version = "v0.0.0";
8-
let build = "(0)";
98
let directory = "init";
109
11-
window.APP = {
12-
show: () => {},
13-
printVersion: (v, b) => {
14-
version = v;
15-
build = b;
16-
},
17-
printDirectory: (d) => {
18-
directory = d;
19-
},
10+
window.webapp = {
11+
updateDirectory: (newDir) => (directory = newDir),
2012
};
2113
14+
async function initialize() {
15+
const app = await webkit.postMessage("INIT");
16+
directory = app.directory;
17+
return app;
18+
}
19+
2220
function changeDirectory() {
23-
window.webkit?.messageHandlers.controller.postMessage("CHANGE_DIRECTORY");
21+
webkit.postMessage("CHANGE_DIRECTORY");
2422
}
2523
2624
function openDirectory() {
27-
window.webkit?.messageHandlers.controller.postMessage("OPEN_DIRECTORY");
25+
webkit.postMessage("OPEN_DIRECTORY");
2826
}
2927
</script>
3028

3129
<main>
32-
<div class="section icons">
33-
<img class="icon" src={icon} alt="Userscripts App Icon" draggable="false" />
34-
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
35-
<div class="logo">{@html logo}</div>
36-
<div class="version">
37-
{#if import.meta.env.GIT_TAG && import.meta.env.GIT_COMMIT}
38-
<a href="{baseUrl}/releases/tag/{import.meta.env.GIT_TAG}">
39-
{import.meta.env.GIT_TAG}
40-
</a>
41-
(<a href="{baseUrl}/commit/{import.meta.env.GIT_COMMIT}">
42-
{import.meta.env.GIT_COMMIT.slice(0, 7)}
43-
</a>)
44-
{:else}
45-
<span>{version}</span>
46-
<span>{build}</span>
47-
{/if}
30+
{#await initialize() then app}
31+
<div class="section icons">
32+
<img
33+
alt="Userscripts App Icon"
34+
class="icon"
35+
draggable="false"
36+
src={icon}
37+
/>
38+
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
39+
<div class="logo">{@html logo}</div>
40+
<div class="version">
41+
{#if import.meta.env.GIT_TAG && import.meta.env.GIT_COMMIT}
42+
<a href="{baseUrl}/releases/tag/{import.meta.env.GIT_TAG}">
43+
{import.meta.env.GIT_TAG}
44+
</a>
45+
(<a href="{baseUrl}/commit/{import.meta.env.GIT_COMMIT}">
46+
{import.meta.env.GIT_COMMIT.slice(0, 7)}
47+
</a>)
48+
{:else}
49+
<span>v{app.version}</span>
50+
<span>({app.build})</span>
51+
{/if}
52+
</div>
4853
</div>
49-
</div>
50-
<div class="section guide">
51-
<p>
52-
You can turn on the Userscripts iOS Safari extension in Settings or
53-
Safari, then use the extension in Safari. Please refer to the "Usage"
54-
section in the
55-
<a
56-
href="{baseUrl}/blob/{import.meta.env.GIT_TAG ??
57-
'main'}/README.md#usage">README of this version</a
58-
>.
59-
</p>
60-
</div>
61-
<div class="section action">
62-
<button id="changedir" on:click={changeDirectory}>
63-
Change Userscripts Directory
64-
</button>
65-
<div class="current">CURRENT DIRECTORY:</div>
66-
<button id="directory" class="link" on:click={openDirectory}>
67-
{directory}
68-
</button>
69-
</div>
54+
<div class="section guide">
55+
<p>
56+
You can turn on the Userscripts iOS Safari extension in Settings or
57+
Safari, then use the extension in Safari. Please refer to the "Usage"
58+
section in the
59+
<a
60+
href="{baseUrl}/blob/{import.meta.env.GIT_TAG ??
61+
'main'}/README.md#usage">README of this version</a
62+
>.
63+
</p>
64+
</div>
65+
<div class="section action">
66+
<button id="changedir" on:click={changeDirectory}>
67+
Change Userscripts Directory
68+
</button>
69+
<div class="current">CURRENT DIRECTORY:</div>
70+
<button id="directory" class="link" on:click={openDirectory}>
71+
{directory}
72+
</button>
73+
</div>
74+
{:catch error}
75+
<div class="section">
76+
{error}
77+
</div>
78+
{/await}
79+
7080
<div class="section footer">
7181
<div class="links">
7282
<a href="{baseUrl}/blob/{import.meta.env.GIT_TAG ?? 'main'}/README.md"

src/app/global.d.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,25 @@
55

66
declare global {
77
interface Window {
8-
APP: {
9-
show: (
10-
platform: "ios" | "mac",
11-
enabled: boolean,
12-
useSettingsInsteadOfPreferences: boolean,
13-
) => void;
14-
printVersion: (v: string, b: string) => void;
15-
printDirectory: (d: string) => void;
8+
webapp: {
9+
updateDirectory: (directory: string) => void;
1610
};
1711
webkit: {
1812
messageHandlers: {
1913
controller: {
20-
postMessage: function;
14+
postMessage: <T extends MessageBody>(
15+
message: T,
16+
) => Promise<MessageReply<T>>;
2117
};
2218
};
2319
};
2420
}
2521
}
2622

23+
type MessageBody = "INIT" | "CHANGE_DIRECTORY" | "OPEN_DIRECTORY";
24+
25+
type MessageReply<T> = T extends "INIT"
26+
? { build: string; version: string; directory: string }
27+
: void;
28+
2729
export {};

xcode/App-Shared/ViewController.swift

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import WebKit
22

33
private let logger = USLogger(#fileID)
44

5-
class ViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler, UIDocumentPickerDelegate {
5+
class ViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandlerWithReply, UIDocumentPickerDelegate {
66

77
@IBOutlet var webView: WKWebView!
88

@@ -13,7 +13,7 @@ class ViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHan
1313
// https://developer.apple.com/documentation/webkit/wkwebviewconfiguration/2875766-seturlschemehandler
1414
configuration.setURLSchemeHandler(USchemeHandler(), forURLScheme: AppWebViewUrlScheme)
1515
// https://developer.apple.com/documentation/webkit/wkusercontentcontroller
16-
configuration.userContentController.add(self, name: "controller")
16+
configuration.userContentController.addScriptMessageHandler(self, contentWorld: .page, name: "controller")
1717
// https://developer.apple.com/documentation/webkit/wkwebview
1818
self.webView = WKWebView(frame: .zero, configuration: configuration)
1919
// https://developer.apple.com/documentation/webkit/wknavigationdelegate
@@ -40,12 +40,11 @@ class ViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHan
4040
webView.load(URLRequest(url: URL(string: "\(AppWebViewUrlScheme):///")!))
4141
}
4242

43-
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
44-
let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "??"
45-
let buildNumber = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "??"
46-
webView.evaluateJavaScript("APP.printVersion('v\(appVersion)', '(\(buildNumber))')")
47-
webView.evaluateJavaScript("APP.printDirectory('\(getCurrentScriptsDirectoryString())')")
48-
}
43+
// https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455629-webview
44+
// DOMContentLoaded
45+
// func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
46+
// webView.evaluateJavaScript("")
47+
// }
4948

5049
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
5150
if navigationAction.navigationType == .linkActivated {
@@ -79,32 +78,48 @@ class ViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHan
7978
decisionHandler(.allow)
8079
}
8180

82-
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
81+
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) async -> (
82+
Any?,
83+
String?
84+
) {
8385
guard let name = message.body as? String else {
8486
logger?.error("\(#function, privacy: .public) - Userscripts iOS received a message without a name")
85-
return
87+
return (nil, "bad message body")
8688
}
87-
if name == "CHANGE_DIRECTORY" {
89+
switch name {
90+
case "INIT":
91+
let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "0.0.0"
92+
let buildNumber = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "0"
93+
return ([
94+
"build": buildNumber,
95+
"version": appVersion,
96+
"directory": getCurrentScriptsDirectoryString(),
97+
], nil)
98+
case "CHANGE_DIRECTORY":
8899
// https://developer.apple.com/documentation/uikit/view_controllers/providing_access_to_directories
89100
logger?.info("\(#function, privacy: .public) - Userscripts iOS has requested to set the readLocation")
90101
let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: [.folder])
91102
documentPicker.delegate = self
92103
documentPicker.directoryURL = getDocumentsDirectory()
93104
present(documentPicker, animated: true, completion: nil)
94-
}
95-
if name == "OPEN_DIRECTORY" {
105+
break
106+
case "OPEN_DIRECTORY":
96107
guard var components = URLComponents(url: Preferences.scriptsDirectoryUrl, resolvingAgainstBaseURL: true) else {
97-
return
108+
return (nil, "ScriptsDirectoryUrl malformed")
98109
}
99110
components.scheme = "shareddocuments"
100111
if let url = components.url, UIApplication.shared.canOpenURL(url) {
101-
UIApplication.shared.open(url)
112+
await UIApplication.shared.open(url)
102113
}
114+
break
115+
default:
116+
return (nil, "Unexpected message body")
103117
}
118+
return (nil, nil)
104119
}
105120

106121
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) {
107122
Preferences.scriptsDirectoryUrl = url
108-
webView.evaluateJavaScript("APP.printDirectory('\(getCurrentScriptsDirectoryString())')")
123+
webView.evaluateJavaScript("webapp.updateDirectory('\(getCurrentScriptsDirectoryString())')")
109124
}
110125
}

0 commit comments

Comments
 (0)