更新弃用的 webkit objc 项目以在 javascript 内启用本机代码 运行
Update deprecated webkit objc items to enable native code running within javascript
我正在使用基于遗留 webkit 的应用程序在 macOS 原生应用程序上生成表单(cocoa 用 objective-c 编写的应用程序)
在 javascript 加载到视图之前调用以下回调,
并允许在即将加载的 javascript 中使用当前 class 代码 (objc)。
- (void)webView:(WebView *)webView windowScriptObjectAvailable:(WebScriptObject *)windowScriptObject {
[windowScriptObject setValue:self forKey:@"app"];
}
不幸的是,它早就被弃用了,我想使用 WKWebView
的 webView 对象的更新替代品。然而,上面的回调是来自 WebFrameLoadDelegate
的委托方法,它也被弃用了。也许有人知道如何使用 WKWebView 在 javascript 中注入我们的本机代码?
谢谢
这就是您使用 WKWebView
的方式。 YourWebView
是 UIView 或 ViewController class.
@interface YourWebView () <WKNavigationDelegate, WKScriptMessageHandler>
- (void)injectWSKitScriptInUserContentController:(WKUserContentController*)userContentController;
@end
在 -init 或 -initWithFrame:
中的实现中
self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
self.autoresizesSubviews = YES;
self.wantsLayer = YES;
WKWebViewConfiguration* conf = [[WKWebViewConfiguration alloc] init];
conf.suppressesIncrementalRendering = NO;
conf.mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeAll;
WKUserContentController* userContentController = [[WKUserContentController alloc] init];
[self injectWSKitScriptInUserContentController:userContentController];
[userContentController addScriptMessageHandler:self name:@"yourscript"];
conf.userContentController = userContentController;
#ifdef DEBUG
NSLog(@"Developer Extras Enabled");
[conf.preferences setValue:@YES forKey:@"developerExtrasEnabled"];
#endif
WKWebView *webView = [[WKWebView alloc] initWithFrame:frame configuration:conf];
webView.navigationDelegate = self;
添加webView
查看或任何你需要它的地方,并定义一个注入js的方法。
-(void)injectWSKitScriptInUserContentController:(WKUserContentController*)userContentController {
NSBundle* bundle = [NSBundle bundleForClass:[YourWebView class]];
NSString* scriptLocation = [bundle pathForResource:@"yourscript" ofType:@"js"];
NSString* scriptSource = [NSString stringWithContentsOfFile:scriptLocation encoding:NSUTF8StringEncoding error:nil];
WKUserScript* userScript = [[WKUserScript alloc] initWithSource:scriptSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
[userContentController addUserScript:userScript];
}
然后遵循关于在 YourWebView 中实现的其他内容的协议
例如与您的 webview 交互,例如前进、重新加载、后退等。
最后,您需要添加一个 javascript 文件作为您应用程序的起点。 "yourscript.js"如上。
(function() {
"use strict";
var Events = {
listeners: { },
gc: function() {
var events = Object.keys(this.listeners)
for (var i = events.length - 1; i >= 0; i -= 1) {
var eventName = events[i],
listeners = this.listeners[eventName]
if (listeners.length === 0) {
delete this.listeners[eventName]
}
}
},
once: function(name, listener) {
if (name in this.listeners) {
this.listeners[name].push({ oneshot: true, listener: listener })
return
}
this.listeners[name] = [
{ oneshot: true, listener: listener },
]
},
on: function(name, listener) {
if (name in this.listeners) {
this.listeners[name].push({ listener: listener })
return
}
this.listeners[name] = [ { listener: listener } ]
},
off: function(name, listener) {
if ( ! (name in this.listeners)) {
return
}
var listeners = this.listeners[name]
for (var i = listeners.length - 1; i >= 0; i -= 1) {
if (listeners[i].listener === listener) {
listeners.splice(i, 1)
return
}
}
},
trigger: function(name, arg) {
if ( ! (name in this.listeners)) {
return
}
var event = { stopIteration: false, data: arg }
var listeners = this.listeners[name]
for (var i = 0; i < listeners.length; i += 1) {
var listener = listeners[i]
try {
listener.listener(event)
} catch (e) { }
if (listener.oneshot) {
listeners.splice(i, 1)
i -= 1
}
}
this.gc()
},
}
var ETimeout = new Error('WSKit: configuration timeout'),
_config = { resolve: null, reject: null, resolved: false }
window.WSKit = {
configuration: new Promise(function(resolve, reject) {
_config.resolve = resolve
_config.reject = reject
}),
addEventListener: function(name, listener, config) {
config = config || { }
if (config.oneshot) {
Events.once(name, listener)
} else {
Events.on(name, listener)
}
},
removeEventListener: function(name, listener) {
Events.off(name, listener)
},
dispatchEvent: function(name, arg) {
Events.trigger(name, arg)
},
}
setTimeout(function() {
if ( ! _config.resolved) {
_config.reject(ETimeout)
}
}, 5000)
WSKit.addEventListener('configure', function(ev) {
_config.resolve(ev.data)
})
window.webkit.messageHandlers.webscreen.postMessage('obtainconfiguration')
})();
这应该很管用
我正在使用基于遗留 webkit 的应用程序在 macOS 原生应用程序上生成表单(cocoa 用 objective-c 编写的应用程序)
在 javascript 加载到视图之前调用以下回调, 并允许在即将加载的 javascript 中使用当前 class 代码 (objc)。
- (void)webView:(WebView *)webView windowScriptObjectAvailable:(WebScriptObject *)windowScriptObject {
[windowScriptObject setValue:self forKey:@"app"];
}
不幸的是,它早就被弃用了,我想使用 WKWebView
的 webView 对象的更新替代品。然而,上面的回调是来自 WebFrameLoadDelegate
的委托方法,它也被弃用了。也许有人知道如何使用 WKWebView 在 javascript 中注入我们的本机代码?
谢谢
这就是您使用 WKWebView
的方式。 YourWebView
是 UIView 或 ViewController class.
@interface YourWebView () <WKNavigationDelegate, WKScriptMessageHandler>
- (void)injectWSKitScriptInUserContentController:(WKUserContentController*)userContentController;
@end
在 -init 或 -initWithFrame:
中的实现中self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
self.autoresizesSubviews = YES;
self.wantsLayer = YES;
WKWebViewConfiguration* conf = [[WKWebViewConfiguration alloc] init];
conf.suppressesIncrementalRendering = NO;
conf.mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeAll;
WKUserContentController* userContentController = [[WKUserContentController alloc] init];
[self injectWSKitScriptInUserContentController:userContentController];
[userContentController addScriptMessageHandler:self name:@"yourscript"];
conf.userContentController = userContentController;
#ifdef DEBUG
NSLog(@"Developer Extras Enabled");
[conf.preferences setValue:@YES forKey:@"developerExtrasEnabled"];
#endif
WKWebView *webView = [[WKWebView alloc] initWithFrame:frame configuration:conf];
webView.navigationDelegate = self;
添加webView
查看或任何你需要它的地方,并定义一个注入js的方法。
-(void)injectWSKitScriptInUserContentController:(WKUserContentController*)userContentController {
NSBundle* bundle = [NSBundle bundleForClass:[YourWebView class]];
NSString* scriptLocation = [bundle pathForResource:@"yourscript" ofType:@"js"];
NSString* scriptSource = [NSString stringWithContentsOfFile:scriptLocation encoding:NSUTF8StringEncoding error:nil];
WKUserScript* userScript = [[WKUserScript alloc] initWithSource:scriptSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
[userContentController addUserScript:userScript];
}
然后遵循关于在 YourWebView 中实现的其他内容的协议 例如与您的 webview 交互,例如前进、重新加载、后退等。
最后,您需要添加一个 javascript 文件作为您应用程序的起点。 "yourscript.js"如上。
(function() {
"use strict";
var Events = {
listeners: { },
gc: function() {
var events = Object.keys(this.listeners)
for (var i = events.length - 1; i >= 0; i -= 1) {
var eventName = events[i],
listeners = this.listeners[eventName]
if (listeners.length === 0) {
delete this.listeners[eventName]
}
}
},
once: function(name, listener) {
if (name in this.listeners) {
this.listeners[name].push({ oneshot: true, listener: listener })
return
}
this.listeners[name] = [
{ oneshot: true, listener: listener },
]
},
on: function(name, listener) {
if (name in this.listeners) {
this.listeners[name].push({ listener: listener })
return
}
this.listeners[name] = [ { listener: listener } ]
},
off: function(name, listener) {
if ( ! (name in this.listeners)) {
return
}
var listeners = this.listeners[name]
for (var i = listeners.length - 1; i >= 0; i -= 1) {
if (listeners[i].listener === listener) {
listeners.splice(i, 1)
return
}
}
},
trigger: function(name, arg) {
if ( ! (name in this.listeners)) {
return
}
var event = { stopIteration: false, data: arg }
var listeners = this.listeners[name]
for (var i = 0; i < listeners.length; i += 1) {
var listener = listeners[i]
try {
listener.listener(event)
} catch (e) { }
if (listener.oneshot) {
listeners.splice(i, 1)
i -= 1
}
}
this.gc()
},
}
var ETimeout = new Error('WSKit: configuration timeout'),
_config = { resolve: null, reject: null, resolved: false }
window.WSKit = {
configuration: new Promise(function(resolve, reject) {
_config.resolve = resolve
_config.reject = reject
}),
addEventListener: function(name, listener, config) {
config = config || { }
if (config.oneshot) {
Events.once(name, listener)
} else {
Events.on(name, listener)
}
},
removeEventListener: function(name, listener) {
Events.off(name, listener)
},
dispatchEvent: function(name, arg) {
Events.trigger(name, arg)
},
}
setTimeout(function() {
if ( ! _config.resolved) {
_config.reject(ETimeout)
}
}, 5000)
WSKit.addEventListener('configure', function(ev) {
_config.resolve(ev.data)
})
window.webkit.messageHandlers.webscreen.postMessage('obtainconfiguration')
})();
这应该很管用