테스트 사이트 - 개발 중인 베타 버전입니다

The complete guide to React Native WebView

· 5년 전 · 7929

간단히 말해서 WebView 는 React Native 앱에서 웹 페이지를 로드하는 데 사용되는 구성 요소입니다. 이전에는 React Native 에서 즉시 사용할 수 있었지만 이제 React Native 코어에서 제거되어 React Native Community 라이브러리의 구성 요소로 추가됩니다. 자세한 내용은 The Slimmening proposal을 참조하십시오. 이제 react-native-webview 라이브러리를 설치해야 합니다.

Platforms supported

저는 React Native 개발자이기도 하므로 앱에서 사용할 라이브러리에 대해 플랫폼간 지원이 얼마나 중요한지 이해합니다. 앱에서 라이브러리를 사용해야 할 때마다 가장 먼저 묻는 것은 크로스 플랫폼인지 여부입니다. react-native-webview 에 대해 걱정할 필요가 없습니다. iOS 및 Android 플랫폼을 모두 지원합니다.

참고: React Native WebView 에 대한 Expo 지원은 Expo SDK v33.0.0로 시작되었습니다.

Getting started

먼저 아래 명령을 실행하여 라이브러리를 설치해야합니다.

// with yarn
$ yarn add react-native-webview

// with npm
$ npm install --save react-native-webview

그런 다음 종속성을 연결하십시오. react-native 0.60 부터 자동 연결은 연결 프로세스를 처리하지만 pod install를 실행하는 것을 잊지 마십시오.

React 네이티브 Objective-C, Swift, Java 또는 Kotlin 코드를 포함하는 네이티브 모듈은 컴파일러가 앱에 포함할 수 있도록 link되어야합니다.

연결하려면 아래 명령을 실행하십시오.

$ react-native link react-native-webview

For iOS:

ios/디렉토리에서 CocoaPods 를 사용하는 경우 다음을 실행하십시오.

$ pod install

For Android:

react-native-webview 버전≥ 6.X.X 를 사용하는 경우 android/gradle.properties를 편집하고 아래 두 줄을 추가하여 프로젝트에서 AndroidX 를 사용하도록 설정하십시오.

android.useAndroidX=true
android.enableJetifier=true

참고 : React Native WebView 를 제거해야하는 경우 react-native unlink react-native-webview를 실행하여 링크를 해제하십시오.

성공적으로 설치했으면 합니다. 어딘가에 갇힌 경우 공식 설치 안내서를 참조하십시오.

이제 간단한 것부터 고급까지 WebView 의 유용한 예와 그 이후의 사용법을 보여 드리겠습니다.

Basic quickstart

WebView 의 기본 속성을 검토하여 시작하겠습니다.

import React, { Component } from 'react';
import { WebView } from 'react-native-webview';

class MyWeb extends Component {
  render() {
    return (
      <WebView
        source={{ uri: 'https://logrocket.com/' }}
        style={{ marginTop: 20 }}
      />
    );
  }
}

먼저 source속성은 URL 또는 HTML 에서 컨텐츠를 가져 오는 데 사용됩니다. URL 로 웹 페이지를 로드하려면 아래와 같이 uri 속성을 가진 객체를 전달해야 합니다.

<WebView
  source={{ uri: 'https://logrocket.com/' }}
/>

Loading inline HTML

위의 URL 로 웹 페이지를 로드하는 방법을 보았습니다. 그러나 HTML 을 직접 로드하려는 경우 아래와 같이 WebView 의 source 속성에서 html 속성을 사용할 수 있습니다.

<WebView
  originWhitelist={['*']}
  source={{ html: '<h1>Hello world</h1>' }}
/>

참고 : HTML 소스를 설정하려면 originWhiteList 속성을 ['*']로 설정해야 합니다.

What is the originWhitelist property anyway?

간단히 말해 originWhitelist속성은 사용자가 WebView 에서 탐색 할 수 있는 위치를 제어합니다. 문자열 배열이 필요하며 기본 whitelisted원점은 http:// 및 https://입니다.

예를 들어, 사용자가 https:// 또는 git://로 시작하는 URI 만 탐색할 수 있도록 하려면 다음과 같이 구현하십시오.

<WebView
  source={{ uri: 'https://logrocket.com/' }}
  originWhitelist={['https://*', 'git://*']}
/>

다른 예를 살펴 보겠습니다.

Loading local HTML files

때로는 WebView 에 로드하려는 HTML 파일이 앱과 함께 로컬로 있습니다.

iOS 에서는 아래 예제와 같이 다른 자산과 마찬가지로 HTML 파일을 가져 오기만 하면 됩니다.

import React, { Component } from 'react';
import { WebView } from 'react-native-webview';

const myHtmlFile = require("./my-asset-folder/local-site.html");

class MyWeb extends Component {
  render() {
    return (
      <WebView source={myHtmlFile} />
    );
  }
}

매우 간단합니다. 정확히 예상했던 것입니다.

그러나 Android 에서는 HTML 파일을 Android 자산 디렉토리에 넣어야합니다. 예를 들어, 안드로이드 앱에 logrocket.html이라는 파일을 로드하려면 안드로이드 자산 디렉토리인 yourProject/android/src/main/assets/로 이동해야 합니다.

그런 다음 아래 예제와 같이 HTML 파일을 로드할 수 있습니다.

import React, { Component } from 'react';
import { WebView } from 'react-native-webview';

class MyWeb extends Component {
  render() {
    return (
      <WebView source={{ uri: "file:///android_asset/logrocket.html" }} />
    );
  }
}

Controlling navigation state changes by user

onNavigationStateChange는 WebView 로딩이 시작되거나 종료될 때 호출되는 함수입니다.

탐색 상태 변경을 제어하고 WebView 에서 탐색하는 것과 다른 작업을 수행해야 하는 경우 이를 수행하는 완벽한 방법입니다. 예를 들면 다음과 같습니다.

import React, { Component } from 'react';
import { WebView } from 'react-native-webview';

class MyWeb extends Component {
  webview = null;

  render() {
    return (
      <WebView
        ref={ref => (this.webview = ref)}
        source={{ uri: 'https://logrocket.com/' }}
        onNavigationStateChange={this.handleWebViewNavigationStateChange}
      />
    );
  }

  handleWebViewNavigationStateChange = newNavState => {
    // newNavState looks something like this:
    // {
    //   url?: string;
    //   title?: string;
    //   loading?: boolean;
    //   canGoBack?: boolean;
    //   canGoForward?: boolean;
    // }
    const { url } = newNavState;
    if (!url) return;

    // handle certain doctypes
    if (url.includes('.pdf')) {
      this.webview.stopLoading();
      // open a modal with the PDF viewer
    }

    // one way to handle a successful form submit is via query strings
    if (url.includes('?message=success')) {
      this.webview.stopLoading();
      // maybe close this view?
    }

    // one way to handle errors is via query string
    if (url.includes('?errors=true')) {
      this.webview.stopLoading();
    }

    // redirect somewhere else
    if (url.includes('google.com')) {
      const newURL = 'https://logrocket.com/';
      const redirectTo = 'window.location = "' + newURL + '"';
      this.webview.injectJavaScript(redirectTo);
    }
  };
}

이 메소드는 해시 URL 변경시 호출되지 않습니다 (예: [https://logrocket.com/users#list](https://logrocket.com/users#list)에서 [https:/ /logrocket.com/users#help](https://logrocket.com/users#help)). 그러나 버전 8.0.0 부터 iOS 에서 onNavigationStateChange를 사용하면 URL 이 #번 변경될 때 트리거됩니다.

How to add support for file uploads

WebView 에서 파일 업로드를 허용하려면 아래 권한을 추가해야 합니다. 아래에서 작업과 플랫폼으로 구분하여 필요한 것을 정확하게 선택할 수 있습니다.

For iOS:

iOS 를 사용한다면 ios/[project]/Info.plist 파일에 권한을 지정하기만 하면 됩니다.

사진 캡처의 경우:

<key>NSCameraUsageDescription</key>
<string>Take pictures for certain activities</string>

갤러리 선택의 경우:

<key>NSPhotoLibraryUsageDescription</key>
<string>Select pictures for certain activities</string>

비디오 녹화의 경우:

<key>NSMicrophoneUsageDescription</key>
<string>Need microphone access for recording videos</string>

For Android:

AndroidManifest.xml에 권한을 추가하십시오. `/Android/app/src/main/AndroidManifest.XML 에 있습니다.

Android 개발을 시작할 때 프로젝트에서 해당 파일을 찾는 데 실제로 문제가 발생했기 때문에 해당 파일 위치를 추가했습니다.

<manifest ...>
  ......

  <!-- this is required only for Android 4.1-5.1 (api 16-22)  -->
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

  ......
</manifest>

<input type="file"/>을 사용한 파일 업로드는 Android 4.4 KitKat 에서 지원되지 않습니다 (자세한 내용은 여기 참조) - 파일 업로드가 지원되는지 확인하려면 isFileUploadSupported()를 사용하여 파일 업로드를 확인할 수 있습니다. 아래 예를 참조하십시오.

WebView.isFileUploadSupported().then(res => {
  if (res === true) {
    // file upload is supported
  } else {
    // file upload is not supported
  }
});

Controlling multiple file uploads

어쨌든 단일 및 다중 파일 업로드를 제어하려면 아래 예제와 같이 input 요소에 다중 속성을 추가하면됩니다.

// multiple file selection
<input type="file" multiple />

// single file selection
<input type="file" />

Adding support for file downloads

예, 사용자가 WebView 에서 파일을 다운로드할 수 있게 하려면 해당 권한을 추가해야 합니다.

For iOS:

iOS 의 경우 ios/[project]/Info.plist 파일에 권한을 지정하기만 하면 됩니다.

갤러리에 저장:

<key>NSPhotoLibraryAddUsageDescription</key>
<string>Save pictures for certain activities.</string>

For Android:

/android/app/src/main/AndroidManifest.xml에 있는 AndroidManifest.xml에 권한을 추가하십시오:

<manifest ...>
  ......

  <!-- this is required to save files on Android  -->
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

  ......
</manifest>

How to inject JavaScript in WebView

때로는 WebView 로 JavaScript 를 실행하려는 상황에 처할 수도 있습니다. 이 경우 WebView 는 다음과 같은 세 가지 방법을 제공합니다.

  1. injectedJavaScript prop
  2. injectJavaScript method
  3. postMessage method 와 onMessage prop

The injectedJavaScript prop

이 메소드는 웹 페이지가 처음으로 로드된 직후 제공된 스크립트를 실행합니다. 페이지가 다시 로드되거나 사용자가 이동하더라도 한 번만 실행됩니다. 예를 들면 다음과 같습니다.

import React, { Component } from 'react';
import { View } from 'react-native';
import { WebView } from 'react-native-webview';

export default class App extends Component {
  render() {
    const myScript = `
      document.body.style.backgroundColor = 'red';
      setTimeout(function() { window.alert('hi') }, 2000);
      true; // note: this is required, or you'll sometimes get silent failures
    `;
    return (
      <View style={{ flex: 1 }}>
        <WebView
          source={{
            uri:
              'https://github.com/react-native-community/react-native-webview',
          }}
          injectedJavaScript={runFirst}
        />
      </View>
    );
  }
}

참고: 이유는 모르겠지만 공식 문서에 따르면 스크립트 끝에 true;가 필요합니다. 사용하지 않으면 때로는 자동 실패가 발생하므로 포함하는 것이 좋습니다.

따라서 위 스크립트에서 배경색을 빨간색으로 설정하고 2 초 후에 hi를 경고합니다. 아래 이미지에서 볼 수 있습니다. myScript는 페이지가 로드되면 실행됩니다.

injectedJavaScriptpropexample.png

What’s going on internally?

iOS 에서 injectedJavaScript는 WebView 에서 evaluateJavaScript:completionHandler:라는 메소드를 실행합니다. 안드로이드에서 injectedJavaScript는 안드로이드 웹뷰에서 evaluateJavascriptWithFallback이라는 메소드를 실행합니다.

앞서 언급했듯이 injectedJavaScript prop 은 컨텐츠 로드후 실행됩니다. 그러나 컨텐츠를 로드하기 전에 JavaScript 코드를 실행해야 하는 경우 어떻게 해야 합니까?

이를 위해 페이지가 처음 로드되기 전에 JavaScript 코드를 실행하는 injectedJavaScriptBeforeContentLoaded라는 또 다른 소품이 있습니다. 페이지가 다시 로드되거나 사용자가 이동하더라도 한번만 실행됩니다. 코드를 실행하기 전에 창, localStorage 또는 문서에 무엇이든 삽입하려는 경우 이 소품을 사용할 수 있습니다.

import React, { Component } from 'react';
import { View } from 'react-native';
import { WebView } from 'react-native-webview';

export default class App extends Component {
  render() {
    const runFirst = `
      window.isNativeApp = true;
      true; // note: this is required, or you'll sometimes get silent failures
    `;
    return (
      <View style={{ flex: 1 }}>
        <WebView
          source={{ uri: 'https://logrocket.com/' }}
          injectedJavaScriptBeforeContentLoaded={runFirst}
        />
      </View>
    );
  }
}

The injectJavaScript method

injectedJavaScript prop 의 단점은 한 번만 실행된다는 것입니다. 그렇기 때문에 WebView 참조에 injectJavaScript라는 메소드를 노출시키는 이유도 있습니다. (이름에 약간의 차이가 있습니다!)

다음은 injectJavaScript 소품을 사용하는 방법입니다.

import React, { Component } from 'react';
import { View } from 'react-native';
import { WebView } from 'react-native-webview';

export default class App extends Component {
  render() {
    const run = `
      document.body.style.backgroundColor = 'blue';
      true;
    `;

    setTimeout(() => {
      this.webref.injectJavaScript(run);
    }, 3000);

    return (
      <View style={{ flex: 1 }}>
        <WebView
          ref={r => (this.webref = r)}
          source={{ uri: 'https://logrocket.com/' }}
        />
      </View>
    );
  }
}

3 초 후에 코드가 실행되고 배경이 파란색이됩니다.

injectJavaScriptmethodexample.png

What’s going on internally?

iOS 에서 injectJavaScript는 WebView 의 evaluateJS:andThen:을 호출합니다. Android 에서 injectJavaScript는 Android WebView 의 evaluateJavascriptWithFallback 메소드를 호출합니다.

The window.ReactNativeWebView.postMessage method and onMessage prop

이전 접근법은 prop 을 사용하여 JavaScript 코드를 주입하는 데 실제로 도움이 됩니다. 그러나 웹 페이지가 React Native 코드로 무언가를 보내거나 통신하려면 어떻게해야합니까? 여기서window.ReactNativeWebView.postMessage 및 onMessage prop 을 사용할 수 있습니다.

웹 페이지에 onMessage 또는 window.ReactNativeWebView.postMessage 메소드를 삽입하지 않도록 설정해야합니다.

import React, { Component } from 'react';
import { View } from 'react-native';
import { WebView } from 'react-native-webview';

export default class App extends Component {
  render() {
    const html = `
      <html>
      <head></head>
      <body>
        <script>
          setTimeout(function () {
            window.ReactNativeWebView.postMessage("Hello!")
          }, 2000)
        </script>
      </body>
      </html>
    `;

    return (
      <View style={{ flex: 1 }}>
        <WebView
          source={{ html }}
          onMessage={event => {
            alert(event.nativeEvent.data);
          }}
        />
      </View>
    );
  }
}

코드의 결과는 Hello!이며 아래 이미지와 같이 경고합니다.

onMessagepropexample.png

Conclusion

이 기사 전체를 읽으면 React Native WebView 에서 사용할 것보다 더 많은 것을 알고 있다고 말할 수 있습니다. 항상 더 많이 아는 것이 좋습니다.

Plug: LogRocket, a DVR for Web apps

1d0cd1srmyo6nbraspxtvbaxfg.png

LogRocket은 마치 자신의 브라우저에서 발생한 것처럼 문제를 재생할 수 있는 프런트엔드 응용 프로그램 모니터링 솔루션입니다. LogRocket 을 사용하면 오류가 발생하는 이유를 추측하거나 사용자에게 스크린 샷 및 로그 덤프를 요청하는 대신 세션을 재생하여 무엇이 잘못되었는지 신속하게 이해할 수 있습니다. 프레임 워크에 관계없이 모든 앱에서 완벽하게 작동하며 Redux, Vuex 및 @ngrx/store 의 추가 컨텍스트를 기록하는 플러그인이 있습니다.

Redux 작업 및 상태 로깅 외에도 LogRocket 은 콘솔 로그, JavaScript 오류, 스택 추적, 헤더 + 본문이 있는 네트워크 요청/응답, 브라우저 메타 데이터 및 사용자 지정 로그를 기록합니다. 또한 DOM 을 계측하여 페이지에 HTML 및 CSS 를 기록하여 가장 복잡한 단일 페이지 앱의 완벽한 픽셀 비디오를 재생성합니다.

무료로 사용해보십시오.

댓글 작성

댓글을 작성하시려면 로그인이 필요합니다.

로그인하기

게시글 목록

번호 제목
1891
1879
1874
1873
1867
1866
1862
1861
1855
1854
1853
1851
1850
1849
1848
1847
1841
1840
1835
1833
1825
1824
1820
1819
1814
1811
1810
1809
1808
1805