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

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

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

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

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

Кто-нибудь имеет опыт работы с этой проблемой?

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

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

Ответ 1

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

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

SHORT ANSWER

Вот шаги:

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

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

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

4) - Авторизовать обход iOS9 ATS для обработки http (а не только https).

И вуаля!

ПОДРОБНЫЙ ОТВЕТ

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

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

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

Учитывая, что ваши файлы с угловыми или 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) Разрешить обход iOS9 ATS для обработки http (а не только https)

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

NSAllowsArbitraryLoads = true

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

Ответ 2

Как я уже сказал, вы делаете мобильное приложение и компилируете его после... У меня была очень похожая проблема. Но для меня окончательная сборка была сделана службой 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

Извините, если я понял, что вы ошибаетесь.

Ответ 3

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

Swift 3.0

  • Добавить пакет GCDWebServer pod "GCDWebServer", "~> 3.0"

  • Нажмите и перетащите свою веб-папку AngularJS в Xcode, и при появлении запроса выберите "Копировать элементы, если необходимо" и "Создать ссылки на папку"

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

    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
    }
    
    }