טעינת תוכן מתוך האפליקציה

תוכל לספק תוכן מבוסס-אינטרנט כמו HTML, JavaScript CSS — כדי שהאפליקציה תשתמש באיסוף סטטי לתוך האפליקציה, מאשר לאחזר את האינטרנט.

תוכן מתוך האפליקציה לא דורש גישה לאינטרנט או צורך רוחב פס של המשתמש. אם המיקום שהתוכן מיועד במיוחד ל-WebView, כלומר תלויה בתקשורת עם אפליקציית נייטיב, אז המשתמשים לא יוכלו לטעון אותו בדפדפן אינטרנט.

עם זאת, יש כמה חסרונות לתוכן בתוך האפליקציה. עדכון תוכן מבוסס-אינטרנט צריך לשלוח עדכון חדש לאפליקציה, ויכול להיות שיש אי-התאמות בין התוכן שבאתר לבין מה שמופיע באפליקציה במכשיר, אם למשתמשים יש גרסאות מיושנות של האפליקציה.

WebViewAssetLoader

WebViewAssetLoader הוא בדרך גמישה ומתקדמת לטעינה של תוכן בתוך האפליקציה אובייקט WebView. הכיתה הזו תומכת הבאים:

  • טעינת תוכן עם כתובת URL מסוג HTTP(S) לצורך תאימות עם Same-origin .
  • טעינת משאבי משנה כמו JavaScript , CSS, תמונות ו-iframes.

כוללים את WebViewAssetLoader בקובץ הפעילות הראשי. זוהי דוגמה דוגמה לטעינת תוכן פשוט מהאינטרנט מתיקיית הנכסים:

Kotlin

private class LocalContentWebViewClient(private val assetLoader: WebViewAssetLoader) : WebViewClientCompat() {
    @RequiresApi(21)
    override fun shouldInterceptRequest(
        view: WebView,
        request: WebResourceRequest
    ): WebResourceResponse? {
        return assetLoader.shouldInterceptRequest(request.url)
    }

    // To support API < 21.
    override fun shouldInterceptRequest(
        view: WebView,
        url: String
    ): WebResourceResponse? {
        return assetLoader.shouldInterceptRequest(Uri.parse(url))
    }
}

Java

private static class LocalContentWebViewClient extends WebViewClientCompat {

    private final WebViewAssetLoader mAssetLoader;

    LocalContentWebViewClient(WebViewAssetLoader assetLoader) {
        mAssetLoader = assetLoader;
    }

    @Override
    @RequiresApi(21)
    public WebResourceResponse shouldInterceptRequest(WebView view,
                                     WebResourceRequest request) {
        return mAssetLoader.shouldInterceptRequest(request.getUrl());
    }

    @Override
    @SuppressWarnings("deprecation") // To support API < 21.
    public WebResourceResponse shouldInterceptRequest(WebView view,
                                     String url) {
        return mAssetLoader.shouldInterceptRequest(Uri.parse(url));
    }
}

האפליקציה שלך צריכה להגדיר מכונה של WebViewAssetLoader שתתאים לצרכים שלה. בקטע הבא יש דוגמה.

איך יוצרים נכסים ומשאבים מתוך האפליקציה

WebViewAssetLoader מסתמך על PathHandler כדי לטעון משאבים שתואמים לנתיב משאב נתון. למרות שאתם יכול ליישם את הממשק הזה כדי לאחזר משאבים לפי הצורך על ידי האפליקציה, חבילות של ספריות Webkit AssetsPathHandler וגם ResourcesPathHandler לטעינה של נכסים ומשאבים ב-Android, בהתאמה.

כדי להתחיל, צריך ליצור נכסים ומשאבים לאפליקציה. באופן כללי, חל:

  • קובצי טקסט כמו HTML , JavaScript ו-CSS שייכים לנכסים.
  • תמונות וקבצים בינאריים אחרים שייכים למשאבים.

כדי להוסיף לפרויקט קובצי אינטרנט מבוססי-טקסט:

  1. ב-Android Studio, לוחצים לחיצה ימנית על האפליקציה > מקור > התיקייה הראשית ולאחר מכן בוחרים New > (חדש >) Google Directory.
    תמונה שמוצגים בה תפריטים של ספריית היצירה ב-Android Studio
    איור 1. יוצרים תיקיית נכסים עבור פרויקט.
  2. נותנים לתיקייה את השם 'נכסים'.
    תמונה שמוצגת בה תיקיית הנכסים
    איור 2. נותנים שם לתיקיית הנכסים.
  3. לוחצים לחיצה ימנית על התיקייה נכסים ואז לוחצים על חדש > קובץ. מזינים index.html ומקישים על Return או על מקש Enter.
  4. חוזרים על השלב הקודם כדי ליצור קובץ ריק עבור stylesheet.css
  5. ממלאים את הקבצים הריקים שיצרתם עם התוכן בשני הקודים הבאים דוגמאות.
```html
<!-- index.html content -->

<html>
  <head>
    <!-- Tip: Use relative URLs when referring to other in-app content to give
              your app code the flexibility to change the scheme or domain as
              necessary. -->
    <link rel="stylesheet" href="/assets/stylesheet.css">
  </head>
  <body>
    <p>This file is loaded from in-app content.</p>
    <p><img src="/res/drawable/android_robot.png" alt="Android robot" width="100"></p>
  </body>
</html>
```

```css
<!-- stylesheet.css content -->

body {
  background-color: lightblue;
}
```

כדי להוסיף לפרויקט קובץ אינטרנט מבוסס-תמונה:

  1. מורידים את Android_symbol_green_RGB.png למחשב המקומי שלכם.

  2. משנים את שם הקובץ לשם android_robot.png.

  3. העברה ידנית של הקובץ לספריית main/res/drawable של הפרויקט ב- לכונן הקשיח שלך.

איור 4 מציג את התמונה שהוספת והטקסט מדוגמאות הקוד הקודמות מעובד באפליקציה.

תמונה שמציגה פלט שעבר רינדור של אפליקציה
איור 4. קובץ HTML וקובץ תמונה בתוך האפליקציה מעובד באפליקציה.

כדי להשלים את האפליקציה:

  1. רושמים את ה-handlers ומגדירים את AssetLoader באמצעות הוספת את הקוד הבא ל-method onCreate():

    Kotlin

    val assetLoader = WebViewAssetLoader.Builder()
                           .addPathHandler("/assets/", AssetsPathHandler(this))
                           .addPathHandler("/res/", ResourcesPathHandler(this))
                           .build()
    webView.webViewClient = LocalContentWebViewClient(assetLoader)
    

    Java

    final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
             .addPathHandler("/assets/", new WebViewAssetLoader.AssetsPathHandler(this))
             .addPathHandler("/res/", new WebViewAssetLoader.ResourcesPathHandler(this))
             .build();
    mWebView.setWebViewClient(new LocalContentWebViewClient(assetLoader));
    
  2. כדי לטעון את התוכן, מוסיפים את הקוד הבא ל-method onCreate():

    Kotlin

    webView.loadUrl("https://appassets.androidplatform.net/assets/index.html")
    

    Java

    mWebView.loadUrl("https://appassets.androidplatform.net/assets/index.html");
    

שילוב תוכן מתוך האפליקציה עם משאבים מהאתר

ייתכן שהאפליקציה תצטרך לטעון שילוב של תוכן מתוך האפליקציה ותוכן אינטרנט, כמו דף HTML בתוך האפליקציה שהסגנון של משתמש בשירות ה-CSS של האתר. בתרחיש לדוגמה הזה יש תמיכה ב-WebViewAssetLoader. אם אף אחד מכונות PathHandler יכולות למצוא משאב לנתיב הנתון, WebView נופל בחזרה לטעינת תוכן מהאינטרנט. אם משלבים תוכן מתוך האפליקציה עם משאבים מהאתר שלכם, שיריוּן נתיבי ספריות, כמו /assets/ או /resources/ למשאבים מתוך האפליקציה. עדיף להימנע משמירת משאבים האתר במיקומים האלה.

Kotlin

val assetLoader = WebViewAssetLoader.Builder()
                        .setDomain("example.com") // Replace this with your website's domain.
                        .addPathHandler("/assets/", AssetsPathHandler(this))
                        .build()

webView.webViewClient = LocalContentWebViewClient(assetLoader)
val inAppHtmlUrl = "https://example.com/assets/index.html"
webView.loadUrl(inAppHtmlUrl)
val websiteUrl = "https://example.com/website/data.json"

// JavaScript code to fetch() content from the same origin.
val jsCode = "fetch('$websiteUrl')" +
        ".then(resp => resp.json())" +
        ".then(data => console.log(data));"

webView.evaluateJavascript(jsCode, null)

Java

final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
           .setDomain("example.com") // Replace this with your website's domain.
           .addPathHandler("/assets/", new AssetsPathHandler(this))
           .build();

mWebView.setWebViewClient(new LocalContentWebViewClient(assetLoader));
String inAppHtmlUrl = "https://example.com/assets/index.html";
mWebView.loadUrl(inAppHtmlUrl);
String websiteUrl = "https://example.com/website/data.json";

// JavaScript code to fetch() content from the same origin.
String jsCode = "fetch('" + websiteUrl + "')" +
      ".then(resp => resp.json())" +
      ".then(data => console.log(data));";

mWebView.evaluateJavascript(jsCode, null);

אפשר לצפות בהדגמה של WebView במכשיר מ-GitHub דוגמה לדף HTML בתוך האפליקציה שמאחזר נתוני JSON שמתארחים באינטרנט.

loadDataWithBaseURL

כשצריך לטעון רק דף HTML באפליקציה ואין צורך ליירט אותו במשאבי משנה, כדאי להשתמש loadDataWithBaseURL() שלא צריך בו נכסי אפליקציה. אפשר להשתמש בו כמו שמוצג בקוד הבא דוגמה:

Kotlin

val html = "<html><body><p>Hello world</p></body></html>"
val baseUrl = "https://example.com/"

webView.loadDataWithBaseURL(baseUrl, html, "text/html", null, baseUrl)

Java

String html = "<html><body><p>Hello world</p></body></html>";
String baseUrl = "https://example.com/";

mWebView.loadDataWithBaseURL(baseUrl, html, "text/html", null, baseUrl);

חשוב לבחור את ערכי הארגומנטים בקפידה. מה כדאי לעשות?

  • baseUrl: זוהי כתובת ה-URL שבה תוכן ה-HTML שלך נטען. זו חייבת להיות כתובת ה-URL של HTTP(S).
  • data: זהו תוכן ה-HTML שרוצים להציג כמחרוזת.
  • mimeType: בדרך כלל צריך להגדיר את הערך text/html.
  • encoding: לא נעשה שימוש בהרשאה הזו כאשר baseUrl היא כתובת URL מסוג HTTP(S), ולכן היא יכולה להיות מוגדר ל-null.
  • historyUrl: מוגדר לערך זהה ל-baseUrl.

מומלץ מאוד להשתמש בכתובת URL מסוג HTTP(S) בתור baseUrl, כי זה עוזר צריך לוודא שהאפליקציה תואמת למדיניות המקור הזהה.

אם לא מצאת baseUrl מתאים לתוכן שלך וברצונך להשתמש בו loadData(), צריך לקודד את התוכן באמצעות קידוד באחוזים או Base64 בקידוד. מומלץ מאוד לבחור בקידוד Base64 ולהשתמש בממשקי API של Android לקידוד זאת באופן פרוגרמטי, כפי שמוצג בדוגמת הקוד הבאה:

Kotlin

val encodedHtml: String = Base64.encodeToString(html.toByteArray(), Base64.NO_PADDING)

webView.loadData(encodedHtml, mimeType, "base64")

Java

String encodedHtml = Base64.encodeToString(html.getBytes(), Base64.NO_PADDING);

mWebView.loadData(encodedHtml, mimeType, "base64");

דברים שכדאי להימנע מהם

יש עוד כמה דרכים לטעינת תוכן בתוך האפליקציה, אבל מומלץ מאוד להשתמש בהן נגדם:

  • כתובות URL מסוג file:// וכתובות URL מסוג data: נחשבות למקורות אטומים, כלומר, הם לא יכולים לנצל ממשקי API חזקים לאינטרנט, fetch() או XMLHttpRequest. מערכת loadData() משתמשת ב-data: כתובות URL באופן פנימי, לכן אנחנו ממליצים להשתמש WebViewAssetLoader או loadDataWithBaseURL() במקום זאת.
  • למרות WebSettings.setAllowFileAccessFromFileURLs() וגם WebSettings.setAllowUniversalAccessFromFileURLs() יכול לעקוף את הבעיות הקשורות ל-file:// כתובות URL, מומלץ לא להגדיר את ההתראות האלה אל true כי האפליקציה שלך חשופה לפרצת אבטחה שמנצלות לרעה. מומלץ להגדיר במפורש את הערכים האלה כ-false בכל רמות ה-API כדי לקבל את האבטחה החזקה ביותר.
  • מאותן סיבות, אנחנו ממליצים להימנע מfile://android_assets/ וגם file://android_res/ כתובות URL. AssetsHandler וResourcesHandler כיתות אלה נועדו לשמש כהחלפות.
  • עדיף להימנע משימוש MIXED_CONTENT_ALWAYS_ALLOW בדרך כלל ההגדרה הזו לא נחוצה והיא פוגעת באבטחת האפליקציה. אנחנו ממליצים לטעון את התוכן באפליקציה באותה סכמה – HTTP או HTTPS – כמשאבי האתר שלכם ולהשתמש בו MIXED_CONTENT_COMPATIBILITY_MODE או MIXED_CONTENT_NEVER_ALLOW, לפי הצורך.