AngularJS на WKWebView: какое-либо решение для обработки файла: // на iOS 9?

Я переношу огромное приложение angularJS на iOS 9 и хотел воспользоваться преимуществами WKWebView (мигрируя с UIWebView). Приложение локально автономно, поэтому все файлы обслуживаются для основного пакета приложения с использованием протокола file://.

К сожалению, кажется, что WKWebView изначально нарушает протокол file:// в iOS 8.x, но некоторый свет пролился, когда я увидел совершенно новый iOS 9 loadFileURL(basePath:, AllowReadAccessToURL:) API.

let readAccessPath = NSURL(string:"app", relativeToURL:bundleURL)?.absoluteURL
webView.loadFileURL(basePath!, allowingReadAccessToURL:readAccessPath!)

Увы, хотя я установил разрешениеReadAccessToURL на корневую папку в моем пакете (приложение/), я получил только «индексный файл», асинхронный файл не загружается.

У кого-нибудь есть опыт в этом вопросе?

[ОБНОВЛЕНИЕ] Я вижу, что мое первоначальное описание проблемы было недостаточно точным. У меня работает HTML. Но мои асинхронные вызовы angularJS на самом деле блокируются сторожевым псом безопасности в среде WebKit.

введите описание изображения здесь введите здесь описание изображения


person Stéphane de Luca    schedule 13.10.2015    source источник
comment
Вы знаете, что можете подключить Safari Web Inspector к WKWebView, чтобы увидеть ошибки в консоли? Это может дать больше подсказок.   -  person Stefan Arentz    schedule 18.10.2015
comment
@stefan arentz Конечно. Я улучшил описание проблемы с помощью снимков экрана.   -  person Stéphane de Luca    schedule 18.10.2015
comment
@stefan arentz Отличная функция!   -  person AppsolutEinfach    schedule 22.06.2016


Ответы (3)


Хотя у меня нет быстрого ответа (я имею в виду быстрое решение), у меня есть решение.

Это включает в себя отказ от протокола file:// и переключение на http:// через localhost.

КОРОТКИЙ ОТВЕТ

Вот шаги:

1) — Установите локальный веб-сервер в своем приложении;

2) — Настройте локальный веб-сервер для обслуживания с локального хоста на заданном порту по вашему выбору;

3) — Настройте делегата, который фактически обслуживает файл из ресурсов вашего приложения с учетом правильного типа MIME;

4) — Разрешить обход ATS iOS9 для обработки http (а не только https).

И вуаля!

ДЕТАЛЬНЫЙ ОТВЕТ

1) Установите локальный веб-сервер в своем приложении;

Установите GCDWebServer из репозитория Github: https://github.com/swisspol/GCDWebServer.

2) Настройте локальный веб-сервер для обслуживания с локального хоста на заданном порту вашего компьютера.

Учитывая тот факт, что файлы приложений angularjs или HTML находятся в папке «приложение» в папке ресурсов.

В вашем 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) Разрешить обход ATS iOS9 для обработки http (а не только https)

В вашем файле info.plist в Xcode вы должны добавить словарь с именем «Настройки безопасности транспорта приложений» со следующим ключом-значением:

NSAllowsArbitraryLoads = истина

Надеюсь, поможет. Любой, кто наткнется на что-то более простое, может ответить!

person Stéphane de Luca    schedule 03.11.2015

Как я могу сказать, вы делаете мобильное приложение и компилируете его после... У меня была довольно похожая проблема. Но для меня окончательную сборку сделал сервис adobe build.phonegap. И там единственное, что мне нужно было сделать, это добавить плагин cordova-whitelist-plugin в config.xml вот так

< gap:plugin name="cordova-plugin-whitelist" source="npm" version="1.0.0" />

И чем добавить разрешение на доступ к таким ссылкам

<allow-intent href="file:///*/*" />

также в config.xml

Извините, если я вас неправильно понял.

person Anastasiya    schedule 22.10.2015
comment
Увы, я не использую никаких сторонних технологий. - person Stéphane de Luca; 04.11.2015

Я бы рекомендовал использовать GCDWebServer, вы можете запустить локальный веб-сервер как http://localhost.

Свифт 3.0

  1. Добавьте модуль GCDWebServer pod "GCDWebServer", "~> 3.0"

  2. Щелкните и перетащите веб-папку AngularJS в Xcode, а при появлении запроса выберите «Копировать элементы, если необходимо» и «Создать ссылки на папки».

  3. Используйте этот код в своем контроллере для запуска локального веб-сервера.

    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
    }
    
    }
    
person Brad    schedule 12.10.2017