Вы действительно понимаете веб-просмотр?

внешний интерфейс JavaScript

Автор | Лу Юньхай

Пишите впереди:

WebviewЭволюция нашей клиентской разработки со стороны ПК на мобильную сторону является важной опорой.Теперь приложения и веб-просмотры, которые все используют каждый день, играют свою роль. Далее давайте посмотрим на мир из веб-просмотра.

1. Применимые сценарии

Когда дело доходит до сценариев приложений, вы можете наиболее интуитивно представить некоторые страницы, встроенные в приложение, которые предоставляют нам различные взаимодействия, как показано на рисунке ниже:

На самом деле сценариев применения webview намного больше, чем это.На самом деле, в некоторых программах для ПК наши html-страницы тоже взаимодействуют с нами, но мы одеты в одежду webview.Одежда слишком красивая и мы не нашли ее истинной имея в виду.

Кроме того, есть некоторые взаимодействия в сетевой приставке, и вебвью также имеет дело с нами.Например, некоторые EPG в раннем IPTV работают в вебвью, и они основаны на ядре вебкита, хотя метод взаимодействия, который мы используем, является дистанционным управлением.

Конечно, сегодня мы врежемся с нативной точки зрения и покажем вам реальный веб-просмотр.

2. Взаимодействие с нативным приложением

Сказав так много, на самом деле наиболее часто используемым веб-просмотром является веб-просмотр, встроенный в клиент, размером с статью в публичном аккаунте, которую мы читаем на нашем мобильном телефоне в метро, ​​и размером с некоторые важные процессы взаимодействия в Приложение, которое мы используем. Веб-просмотр открывает страницу m для выполнения. Итак, как m-страница взаимодействует с нативной?

В настоящее время существует два распространенных способа взаимодействия между javascript и клиентом (далее совместно именуемые нативными), один — через JSBridge, а другой — через схему.

1. JSBridge

Во-первых, давайте поговорим о JSBridge. Воплощенная форма на самом деле заключается в том, что когда мы открываем страницу m в нативе, натив внедрит для нас мост под глобальным окном. Этот мост будет содержать различные методы взаимодействия с нативным, такие как определение того, установлены ли сторонние приложения, получение информации о сети и т. д.

Например:

    /**

    * 作用域下的JSBridge,

    * 和实例化后的getNetInfomation,

    * 均根据实际约定情况而定,

    * 这里只是用来举例说明

    */

    const bridge = window.JSBridge;

    console.log(bridge.getNetInfomation());

скопировать код

Сторона IOS

В IOS WebViewJavascriptBridge в основном используется для регистрации, вы можете обратиться к Github WebViewJavascriptBridge

    jsBridge = [WebViewJavascriptBridge bridgeForWebView:webView];

    ...

    [jsBridge registerHandler:@"scanClick" handler:^(id data, WVJBResponseCallback responseCallback) {

    // to do

    }];

скопировать код

Android

В Android нужно регистрироваться через addJavascriptInterface

    class JSBridge{

    @JavascriptInterface //注意这里的注解。出于安全的考虑,4.2 之后强制要求,不然无法从 Javascript 中发起调用

    public void getNetInfomation(){

    // to do

    };

    }

    webView.addJavascriptInterface(new JSBridge();, "JSBridge");

скопировать код
2. Schema url

Если путь Моста заключается во взаимодействии только с нативом, тоschame urlНеважно, что вы можете взаимодействовать внутри нативного, и вы также можете взаимодействовать между приложениями.schemaЭто также основной метод, который мы используем для Zhuanzhuan, он похож на псевдопротокольную ссылку (также называемую унифицированным протоколом перехода), например:

schema://path?param=abc

В веб-просмотре, когда m-страница инициирует запрос схемы, нативная сторона захватит его. Здесь мы можем познакомить вас со знаниями об IOS и Android следующим образом:

Сторона IOS

Взяв в качестве примера UIWebView, в IOS, когда сетевой запрос инициируется в UIWebView, он может быть перехвачен на собственном уровне через делегат, а затем захваченная схема может использоваться для запуска соответствующей функции или бизнес-логики (используя shouldStartLoadWithRequest). . код показывает, как показано ниже:

    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {

    //获取scheme url后自行进行处理

    NSURL *url = [request URL];

    NSString *requestString = [[request URL] absoluteString];

      return YES;

    }

скопировать код

Сторона Android

В Android для захвата URL-адресов схемы можно использовать shouldoverrideurlloading. код показывает, как показано ниже:

    public boolean shouldOverrideUrlLoading(WebView view, String url){

    //读取到url后自行进行分析处理

    //这里注意:如果返回false,则WebView处理链接url,如果返回true,代表WebView根据程序来执行url

    return true;

    }

скопировать код

Выше приведены простые коды захвата схемы для IOS и Android соответственно.Вы можете выполнить соответствующую бизнес-логику в функции в соответствии с вашими потребностями для достижения желаемой функции.


Конечно, только что мы упомянули, что кросс-энд взаимодействие может осуществляться через схему, так как же с ней работать?

На самом деле, для JavaScript это в основном то же самое в веб-просмотре, и он также инициирует запрос схемы, но будут некоторые изменения на нативной стороне.

Во-первых, для популяризации немного знаний для всех, то есть в натвие (включая IOS и Android) вы найдете совпадающие приложения через схему. Среди них IOS нельзя повторять, как и appId, можно повторять Android, при повторе всплывающее окно позволит пользователю выбрать один из них.

Затем, используя эту точку знаний в качестве предзнаменования, вы можете понять, что когда мы инициируем запрос в других приложениях, таких как эта схема, нижний уровень системы (IOS и Android) найдет соответствующее приложение через схему, а затем вытащит это приложение. После запуска приложения соответствующая обработка выглядит следующим образом:

Сторона IOS

На стороне IOS схема передается в качестве параметра предопределенной функции обратного вызова, а затем функция обратного вызова выполняется. Эта функция обратного вызова может быть проанализирована с помощью полученной схемы, а затем направлена ​​на фиксированную страницу в приложении.

    - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{

    // 参数 url 即为获取的 schema

    // to do

    }

скопировать код

Сторона Android

Со стороны Android будет немного хлопотнее.На внешней м странице будет инициирована псевдопротокольная ссылка схемы, и система будет искать по этой схеме.Приложение которое нужно подтянуть нужно иметь файл конфигурации, который примерно выглядит следующим образом:

    <activity

    android:name=".activity.StartActivity"

    android:exported="true">

    <intent-filter>

    <action android:name="android.intent.action.VIEW"/>

    <category android:name="android.intent.category.DEFAULT"/>

    <category android:name="android.intent.category.BROWSABLE"/>

    <data android:scheme="zhuanzhuan"/>

    </intent-filter>

    </activity>

скопировать код

Взяв приведенный выше код в качестве примера, схема в приведенной выше конфигурации является zhuanzhuan, если она"zhuanzhuan://"Ссылка на схему в начале вызовет действие, которое настраивает схему (аналогично коду вышеStartActivity), это действие будет реагировать на этоschema urlВыполнить обработку, например:

    public class StartActivity extends TempBaseActivity {

    Intent intent;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    intent = getIntent();

    Uri uri = intent.getData();

    }

    }

скопировать код

Например, в приведенном выше коде в этом действии вы можете использоватьintent середина getDataметод для получения соответствующей информации о входящей схеме, как показано ниже:

Это также принцип, согласно которому мы можем вызывать собственное приложение в стороннем приложении. Конечно, некоторые приложения на рынке сейчас ограничивают свои схемы, чтобы избежать потери трафика, соответственно можно подтянуть только схемы из белого списка plist, иначе они будут напрямую отфильтровываться. Например, наш отец wx может использовать больше jsApiList после открытия вайтлиста, одним из них является подтягивание схемы, поэтому я не буду здесь вдаваться в подробности... :)

3. Эволюция веб-просмотра

Для веб-просмотра, когда речь заходит об эволюции или трансформации, первое, что приходит мне на ум, — это IOS.WKWebViewТеперь у каждой вещи есть своя неизбежность, давайте взглянем на эту супер версию веб-просмотра.

1. Появление WKWebView

В настоящее время смешанная разработка стала мейнстримом.Чтобы улучшить опыт, WKWebView также родился, когда была выпущена IOS8. До этого сторона IOS использовала UIWebView.

С точки зрения производительности WKWebView будет намного выше, чем UIWebView, что можно расценивать как скачок. Он использует схему кросс-процесса, использует парсер Nitro JS и имеет частоту обновления до 60 кадров в секунду. В то же время он обеспечивает хорошую поддержку страниц H5.Как и UIWebView, он также предоставляет атрибут прогресса загрузки. В настоящее время некоторые интернет-приложения первой линии перешли на WKWebView в IOS, поэтому мы считаем, что не можем отказаться.

Инициализация всего WKWebView также очень проста:

    WKWebView *webView = [[WKWebView alloc] init];

    NSURL *url = [NSURL URLWithString:@"https://m.zhuanzhuan.com"];

    [webView loadRequest:[NSURLRequest requestWithURL:url]];

скопировать код

В основном похож на UIWebView.

2. WKWebView отличается от UIWebView

Улучшение производительности упоминалось выше.Почему объем памяти приложения намного меньше, чем у UIWebView после подключения приложения к WKWebView, главным образом потому, что процесс загрузки и рендеринга веб-страниц, которые потребляют память и производительность, реализуется Процесс WKWebView (WKWebView — это процесс, независимый от приложения). Как показано ниже:

Таким образом, взаимная независимость процессов эквивалентна уменьшению использования памяти всем процессом приложения, и процесс приложения будет более стабильным. Более того, даже в случае сбоя процесса страницы это будет отражать белый экран страницы или сбой загрузки, что не повлияет на сбой всего процесса приложения.

В дополнение к упомянутой выше производительности WKWebView будет иметь на один процесс запроса больше, чем UIWebView. После того, как сервер завершит ответ, он спросит, загружается ли полученный контент в контейнер, который будет более точным, чем управление UIWebView, а также может лучше взаимодействовать с m-page в некотором общении. Примерный процесс выглядит следующим образом:

Прокси-протокол WKWebView — WKNavigationDelegate. По сравнению с UIWebDelegate, первый запрос перехода — это вызов перед загрузкой URL-адреса, чтобы спросить разработчика, следует ли загружать и загружать текущий URL-адрес. UIWebView имеет только один запрос, который является запросом перед запросом, в то время как WKWebView загружается по URL-адресу. После завершения будет отправлен запрос, позволяющий разработчику снова сделать подтверждение в соответствии с веб-контентом, возвращенным сервером.

В-четвертых, долгий путь

Как упоминалось ранее, WKWebView настолько хорош, что на самом деле в его разработке есть некоторые болевые точки. В отличие от UIWebView, многие взаимодействия WKWebView являются асинхронными, поэтому в значительной степени при общении с m страницами стоимость разработки увеличивается.

1. cookie

Во-первых, это проблема с файлами cookie, которая, я думаю, также является ямой WKWebView в отрасли. Раньше была проблема, то есть после завершения входа в IOS, если вы сразу зайдете на страницу m, будет проблема, что cookie состояния входа не может быть получен. Эта проблема не существует в UIWebView.

После расследования было установлено, что основная проблема заключается в том, что UIWebView используется для файлов cookie черезNSHTTPCookieStorageДля унифицированной обработки записывается, когда сервер отвечает, и тогда соответствующий куки будет занесен в заголовок запроса в следующем запросе, чтобы m-страница и натив разделяли значение куки.

Но в WKWebView это не так. Хотя тоже будетNSHTTPCookieStorageдля записи файла cookie, но он не сохраняется в режиме реального времени. И из фактического теста было обнаружено, что разные версии IOS имеют разное время задержки, что не должно быть проблемой для разработчиков m страниц. Точно так же, когда запрос инициирован, он не читается в реальном времени и не может быть синхронизирован с нативным, что приводит к ошибкам логики страницы.

В ответ на эту проблему наше текущее решение состоит в том, чтобы потребовать, чтобы клиент вручную вмешивался в хранение файлов cookie. Сохраните файл cookie, на который служба отвечает локально. Когда запустится следующий веб-просмотр, прочитайте значение локального файла cookie и вручную запишите его в веб-просмотр через собственный. Общий процесс выглядит следующим образом:

Конечно, это не идеальное решение, потому что иногда возникает проблема поражения печенья, когда промежуточная маршрута страницы SPA переключается. Проблема Cookie по-прежнему должна быть исследована и решена нами и нашим клиентам на стороне клиента. Здесь, если у вас есть хорошие предложения и решения, пожалуйста, оставьте сообщение, и мы можем учиться и прогрессировать вместе.

2. Кэш

В дополнение к файлам cookie, проблеме кэширования WKWebView мы также уделяем внимание в последнее время. Поскольку WKWebView по умолчанию использует набор механизмов кэширования, разрешения, которыми могут оперировать разработчики, будут ограничены, особенно версия IOS8, возможно, потому, что WKWebView только родился в то время, он все еще очень несовершенен и вообще не может работать (конечно Я верю, что IOS8 скоро сойдет со сцены истории). Для некоторых статических ресурсов из m страниц изредка кэш не обновляется, что действительно является головной болью.

Но после IOS 9 система предоставляет интерфейс для управления кешемWKWebsiteDataStore.

    // RemoveCache

    NSSet *websiteTypes = [NSSet setWithArray:@[

    WKWebsiteDataTypeDiskCache,

    WKWebsiteDataTypeMemoryCache]];

    NSDate *date = [NSDate dateWithTimeIntervalSince1970:0];

    [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteTypes

    modifiedSince:date

    completionHandler:^{

    }];

скопировать код

Что касается IOS8, то это решается только удалением файла.Как правило, кешированные данные WKWebView будут храниться в этом каталоге:

~/Library/Caches/BundleID/WebKit/

Очистка кеша может быть достигнута путем удаления этого каталога.


Кроме того, в дополнение к болевым точкам, о которых мы упоминали выше, существует также общая проблема веб-просмотра, то есть каждый раз, когда мы открываем страницу в первый раз, должен быть процесс инициализации веб-просмотра, поэтому как сокращение времени инициализации веб-просмотра также является одним из способов повысить скорость открытия страницы.

Конечно, чтобы повысить скорость открытия страницы, наша m-страница также может быть объединена с нативной для создания некоторых автономных решений.В настоящее время в Чжуаньчжуане также есть несколько проектов автономных страниц, которые не будут запущены здесь сегодня.

Говоря об этом, мы также подошли к концу.Возможно, в ближайшем будущем различные появляющиеся технологии прикроют часть ореола веб-просмотра, такие как react-native, апплеты, разработка приложений Android light и т. д., но это бесспорно, что webview не легко уйдет со сцены истории, мы сделаем взаимодействие лучше, и у нас тоже есть чувства. Нет такой вещи, как спокойное время, но некоторые люди идут вперед с тяжелым грузом...