AngularJS 关于 WKWebView:在 iOS 9 上处理 file:// 的任何解决方案?
AngularJS on WKWebView: any solution for handling file:// on iOS 9?
我正在将一个巨大的 angularJS 应用程序移植到 iOS 9 并希望从 WKWebView(从 UIWebView 迁移)中受益。该应用程序是本地独立的,因此所有文件都使用 file:// 协议为应用程序主包提供服务。
不幸的是,听起来 WKWebView 最初在 iOS 8.x 上破坏了 file:// 协议,但是当我看到全新的 iOS 9 loadFileURL(basePath: , allowingReadAccessToURL:) API.
let readAccessPath = NSURL(string:"app", relativeToURL:bundleURL)?.absoluteURL
webView.loadFileURL(basePath!, allowingReadAccessToURL:readAccessPath!)
唉,当我将 allowingReadAccessToURL 设置到我的包 (app/) 中的根文件夹时,我只得到 "index file",没有加载异步文件。
有人对此问题有经验吗?
[更新] 我发现我最初的问题描述不够准确。我有我的 HTML 运行。但是我的异步 angularJS 调用实际上被 WebKit 框架中的安全看门狗阻止了。
正如我所说,您正在制作移动应用程序并在之后对其进行编译...我遇到了非常相似的问题。但对我来说,最终构建是由 adobe build.phonegap 服务完成的。我唯一要做的就是像这样
在 config.xml 中添加 cordova-whitelist-plugin
< gap:plugin name="cordova-plugin-whitelist" source="npm" version="1.0.0" />
然后添加访问此类链接的权限
<allow-intent href="file:///*/*" />
也变成config.xml
对不起,如果我理解错了。
虽然我没有快速的答案(我的意思是快速修复)但我有一个解决方案。
这涉及放弃 file:// 协议并通过本地主机切换到 http://。
简答
步骤如下:
1) — 在您自己的应用中安装本地 Web 服务器;
2) — 设置本地 Web 服务器以在您选择的给定端口从本地主机提供服务;
3) — 在给定正确的 MIME 类型的情况下,设置实际从您的应用资源提供文件的代理;
4) — 授权绕过 iOS9 ATS 以处理 http(而不仅仅是 https)。
瞧!
详细答案
1) 在您自己的应用中安装本地网络服务器;
从其 Github 存储库安装 GCDWebServer:https://github.com/swisspol/GCDWebServer
2) 将本地 Web 服务器设置为在您
的给定端口从本地主机提供服务
鉴于您的 angularjs 或 HTML 应用程序文件位于资源文件夹中的 "app" 文件夹中。
在你的 vc ViewDidLoad:
@implementation ViewController
GCDWebServer* _webServer;
- (void)viewDidLoad
{
[super viewDidLoad];
self.webView = [[WKWebView alloc] initWithFrame:self.view.frame];
[self.view addSubview:self.webView];
self.webView.navigationDelegate = self;
NSURL *bundleURL = [NSBundle mainBundle].bundleURL;
NSURL *basePath = nil;
// Init WebServer
[self initWebServer:[[NSURL URLWithString:@"app" relativeToURL:bundleURL] absoluteURL]];
basePath = [NSURL URLWithString:@"http://localhost:8080/page.html#/home" relativeToURL:nil];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:basePath];
[self.webView loadRequest:request];
}
3) 在给定正确的 MIME 类型的情况下,设置实际从您的应用资源提供文件的委托;
-(void)initWebServer:(NSURL *)basePath {
// Create server
_webServer = [[GCDWebServer alloc] init];
#define GCDWebServer_DEBUG 0
#define GCDWebServer_VERBOSE 1
#define GCDWebServer_INFO 2
#define GCDWebServer_WARNING 3
#define GCDWebServer_ERROR 4
#define GCDWebServer_EXCEPTION 5
[GCDWebServer setLogLevel:GCDWebServer_ERROR];
// Add a handler to respond to GET requests on any URL
[_webServer addDefaultHandlerForMethod:@"GET"
requestClass:[GCDWebServerRequest class]
processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
//NSLog([NSString stringWithFormat:@"WS: loading %@", request]);
NSString * page = request.URL.lastPathComponent;
NSString * path = request.URL.path;
NSString * file = path;
//NSLog(@"WS: loading %@", file);
NSString * fullPath = [NSString stringWithFormat:@"%@%@", basePath, path];
NSString * sFullPath = [fullPath substringFromIndex:7];
BOOL isText = NO;
if([page.lastPathComponent hasSuffix:@"html"]) {
isText = YES;
}
if (isText) {
NSError * error = nil;
NSString * html = [NSString stringWithContentsOfFile:sFullPath encoding:NSUTF8StringEncoding error: &error];
return [GCDWebServerDataResponse responseWithHTML:html];
}
else {
NSData * data = [NSData dataWithContentsOfFile:sFullPath];
if (data !=nil) {
NSString * type = @"image/jpeg";
if ([page.lastPathComponent hasSuffix:@"jpg"]) type = @"image/jpeg";
else if ([page.lastPathComponent hasSuffix:@"png"]) type = @"image/png";
else if ([page.lastPathComponent hasSuffix:@"css"]) type = @"text/css";
else if ([page.lastPathComponent hasSuffix:@"js" ]) type = @"text/javascript";
return [GCDWebServerDataResponse responseWithData:data contentType:type];
}
else {
return [GCDWebServerDataResponse responseWithHTML:[NSString stringWithFormat:@"<html><body><p>404 : unknown file %@ World</p></body></html>", sFullPath]];
//return [GCDWebServerDataResponse responseWithHTML:@"<html><body><p>Hello World</p></body></html>"];
}
}
}];
// Start server on port 8080
[_webServer startWithPort:8080 bonjourName:nil];
NSLog(@"Visiting %@", _webServer.serverURL);
}
4) 授权绕过 iOS9 ATS 以处理 http(而不仅仅是 https)
在 Xcode 的 info.plist 文件中,您必须添加一个名为 "App Transport Security Settings" 的字典,其中包含一个键值,如下所示:
NSAllowsArbitraryLoads = true
希望对您有所帮助。
欢迎任何偶然发现更简单的东西的人回答!
我建议使用 GCDWebServer,您可以 运行 本地 Web 服务器作为 http://localhost
。
Swift 3.0
添加 GCDWebServer pod pod "GCDWebServer", "~> 3.0"
单击并将您的 AngularJS 网络文件夹拖到 Xcode 中,当出现提示时 select 'Copy items if needed' 和 'Create folder references'
在您的控制器中使用此代码 运行 本地主机 Web 服务器
class MainViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate, GIDSignInUIDelegate {
var webView : WKWebView!
var webServer:GCDWebServer?
override func viewDidLoad() {
super.viewDidLoad()
self.webView.load(URLRequest(url: loadDefaultIndexFile()!))
}
private func loadDefaultIndexFile() -> URL? {
self.webServer = GCDWebServer()
let mainBundle = Bundle.main
// The path to my index.html is www/index.html. If using a default public folder then it could be public/index.html
let folderPath = mainBundle.path(forResource: "www", ofType: nil)
self.webServer?.addGETHandler(forBasePath: "/", directoryPath: folderPath!, indexFilename: "index.html", cacheAge: 0, allowRangeRequests: true)
do {
try self.webServer?.start(options: [
"Port": 3000,
"BindToLocalhost": true
]);
}catch{
print(error)
}
// Path should be http://localhost:3000/index.html
return self.webServer?.serverURL
}
}
我正在将一个巨大的 angularJS 应用程序移植到 iOS 9 并希望从 WKWebView(从 UIWebView 迁移)中受益。该应用程序是本地独立的,因此所有文件都使用 file:// 协议为应用程序主包提供服务。
不幸的是,听起来 WKWebView 最初在 iOS 8.x 上破坏了 file:// 协议,但是当我看到全新的 iOS 9 loadFileURL(basePath: , allowingReadAccessToURL:) API.
let readAccessPath = NSURL(string:"app", relativeToURL:bundleURL)?.absoluteURL
webView.loadFileURL(basePath!, allowingReadAccessToURL:readAccessPath!)
唉,当我将 allowingReadAccessToURL 设置到我的包 (app/) 中的根文件夹时,我只得到 "index file",没有加载异步文件。
有人对此问题有经验吗?
[更新] 我发现我最初的问题描述不够准确。我有我的 HTML 运行。但是我的异步 angularJS 调用实际上被 WebKit 框架中的安全看门狗阻止了。
正如我所说,您正在制作移动应用程序并在之后对其进行编译...我遇到了非常相似的问题。但对我来说,最终构建是由 adobe build.phonegap 服务完成的。我唯一要做的就是像这样
在 config.xml 中添加 cordova-whitelist-plugin< gap:plugin name="cordova-plugin-whitelist" source="npm" version="1.0.0" />
然后添加访问此类链接的权限
<allow-intent href="file:///*/*" />
也变成config.xml
对不起,如果我理解错了。
虽然我没有快速的答案(我的意思是快速修复)但我有一个解决方案。
这涉及放弃 file:// 协议并通过本地主机切换到 http://。
简答
步骤如下:
1) — 在您自己的应用中安装本地 Web 服务器;
2) — 设置本地 Web 服务器以在您选择的给定端口从本地主机提供服务;
3) — 在给定正确的 MIME 类型的情况下,设置实际从您的应用资源提供文件的代理;
4) — 授权绕过 iOS9 ATS 以处理 http(而不仅仅是 https)。
瞧!
详细答案
1) 在您自己的应用中安装本地网络服务器;
从其 Github 存储库安装 GCDWebServer:https://github.com/swisspol/GCDWebServer
2) 将本地 Web 服务器设置为在您
的给定端口从本地主机提供服务鉴于您的 angularjs 或 HTML 应用程序文件位于资源文件夹中的 "app" 文件夹中。
在你的 vc ViewDidLoad:
@implementation ViewController
GCDWebServer* _webServer;
- (void)viewDidLoad
{
[super viewDidLoad];
self.webView = [[WKWebView alloc] initWithFrame:self.view.frame];
[self.view addSubview:self.webView];
self.webView.navigationDelegate = self;
NSURL *bundleURL = [NSBundle mainBundle].bundleURL;
NSURL *basePath = nil;
// Init WebServer
[self initWebServer:[[NSURL URLWithString:@"app" relativeToURL:bundleURL] absoluteURL]];
basePath = [NSURL URLWithString:@"http://localhost:8080/page.html#/home" relativeToURL:nil];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:basePath];
[self.webView loadRequest:request];
}
3) 在给定正确的 MIME 类型的情况下,设置实际从您的应用资源提供文件的委托;
-(void)initWebServer:(NSURL *)basePath {
// Create server
_webServer = [[GCDWebServer alloc] init];
#define GCDWebServer_DEBUG 0
#define GCDWebServer_VERBOSE 1
#define GCDWebServer_INFO 2
#define GCDWebServer_WARNING 3
#define GCDWebServer_ERROR 4
#define GCDWebServer_EXCEPTION 5
[GCDWebServer setLogLevel:GCDWebServer_ERROR];
// Add a handler to respond to GET requests on any URL
[_webServer addDefaultHandlerForMethod:@"GET"
requestClass:[GCDWebServerRequest class]
processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
//NSLog([NSString stringWithFormat:@"WS: loading %@", request]);
NSString * page = request.URL.lastPathComponent;
NSString * path = request.URL.path;
NSString * file = path;
//NSLog(@"WS: loading %@", file);
NSString * fullPath = [NSString stringWithFormat:@"%@%@", basePath, path];
NSString * sFullPath = [fullPath substringFromIndex:7];
BOOL isText = NO;
if([page.lastPathComponent hasSuffix:@"html"]) {
isText = YES;
}
if (isText) {
NSError * error = nil;
NSString * html = [NSString stringWithContentsOfFile:sFullPath encoding:NSUTF8StringEncoding error: &error];
return [GCDWebServerDataResponse responseWithHTML:html];
}
else {
NSData * data = [NSData dataWithContentsOfFile:sFullPath];
if (data !=nil) {
NSString * type = @"image/jpeg";
if ([page.lastPathComponent hasSuffix:@"jpg"]) type = @"image/jpeg";
else if ([page.lastPathComponent hasSuffix:@"png"]) type = @"image/png";
else if ([page.lastPathComponent hasSuffix:@"css"]) type = @"text/css";
else if ([page.lastPathComponent hasSuffix:@"js" ]) type = @"text/javascript";
return [GCDWebServerDataResponse responseWithData:data contentType:type];
}
else {
return [GCDWebServerDataResponse responseWithHTML:[NSString stringWithFormat:@"<html><body><p>404 : unknown file %@ World</p></body></html>", sFullPath]];
//return [GCDWebServerDataResponse responseWithHTML:@"<html><body><p>Hello World</p></body></html>"];
}
}
}];
// Start server on port 8080
[_webServer startWithPort:8080 bonjourName:nil];
NSLog(@"Visiting %@", _webServer.serverURL);
}
4) 授权绕过 iOS9 ATS 以处理 http(而不仅仅是 https)
在 Xcode 的 info.plist 文件中,您必须添加一个名为 "App Transport Security Settings" 的字典,其中包含一个键值,如下所示:
NSAllowsArbitraryLoads = true
希望对您有所帮助。 欢迎任何偶然发现更简单的东西的人回答!
我建议使用 GCDWebServer,您可以 运行 本地 Web 服务器作为 http://localhost
。
Swift 3.0
添加 GCDWebServer pod
pod "GCDWebServer", "~> 3.0"
单击并将您的 AngularJS 网络文件夹拖到 Xcode 中,当出现提示时 select 'Copy items if needed' 和 'Create folder references'
在您的控制器中使用此代码 运行 本地主机 Web 服务器
class MainViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate, GIDSignInUIDelegate { var webView : WKWebView! var webServer:GCDWebServer? override func viewDidLoad() { super.viewDidLoad() self.webView.load(URLRequest(url: loadDefaultIndexFile()!)) } private func loadDefaultIndexFile() -> URL? { self.webServer = GCDWebServer() let mainBundle = Bundle.main // The path to my index.html is www/index.html. If using a default public folder then it could be public/index.html let folderPath = mainBundle.path(forResource: "www", ofType: nil) self.webServer?.addGETHandler(forBasePath: "/", directoryPath: folderPath!, indexFilename: "index.html", cacheAge: 0, allowRangeRequests: true) do { try self.webServer?.start(options: [ "Port": 3000, "BindToLocalhost": true ]); }catch{ print(error) } // Path should be http://localhost:3000/index.html return self.webServer?.serverURL } }