ساخت برنامه های وب در WebView

از WebView برای ارائه یک برنامه وب یا یک صفحه وب به عنوان بخشی از برنامه مشتری استفاده کنید. کلاس WebView یک برنامه افزودنی از کلاس View اندروید است که به شما امکان می دهد صفحات وب را به عنوان بخشی از طرح فعالیت خود نمایش دهید. شامل ویژگی‌های یک مرورگر وب کاملاً توسعه‌یافته، مانند کنترل‌های پیمایش یا نوار آدرس نمی‌شود. تمام کاری که WebView انجام می دهد، به طور پیش فرض، نمایش یک صفحه وب است.

WebView می تواند به شما کمک کند اطلاعاتی را در برنامه خود ارائه دهید که ممکن است نیاز به به روز رسانی داشته باشید، مانند قرارداد کاربر نهایی یا راهنمای کاربر. در برنامه Android خود، می‌توانید یک Activity ایجاد کنید که حاوی WebView است، سپس از آن برای نمایش سند خود که به صورت آنلاین میزبانی شده است استفاده کنید.

WebView همچنین می تواند زمانی که برنامه شما داده هایی را در اختیار کاربر قرار می دهد که برای بازیابی داده ها به اتصال اینترنت نیاز دارد، مانند ایمیل، کمک کند. در این مورد، ممکن است متوجه شوید که ساخت یک WebView در برنامه اندرویدی خود که یک صفحه وب را با تمام داده های کاربر نشان می دهد، به جای انجام یک درخواست شبکه، و سپس تجزیه داده ها و رندر کردن آن در یک طرح بندی اندروید، آسان تر است. در عوض، می‌توانید یک صفحه وب طراحی کنید که برای دستگاه‌های مجهز به Android طراحی شده است و سپس یک WebView در برنامه Android خود پیاده کنید که صفحه وب را بارگیری می‌کند.

این سند نحوه شروع به کار با WebView ، نحوه اتصال جاوا اسکریپت از صفحه وب خود به کد سمت سرویس گیرنده در برنامه Android خود، نحوه مدیریت پیمایش صفحه، و نحوه مدیریت ویندوز هنگام استفاده از WebView را شرح می دهد.

با WebView در نسخه های قبلی اندروید کار کنید

برای استفاده ایمن از قابلیت‌های WebView جدیدتر در دستگاهی که برنامه شما روی آن اجرا می‌شود، کتابخانه AndroidX Webkit را اضافه کنید. این یک کتابخانه ثابت است که می توانید برای استفاده از API های android.webkit که برای نسخه های پلتفرم قبلی در دسترس نیستند، به برنامه خود اضافه کنید.

به صورت زیر آن را به فایل build.gradle خود اضافه کنید:

کاتلین

dependencies {
    implementation("androidx.webkit:webkit:1.8.0")
}

شیار

dependencies {
    implementation ("androidx.webkit:webkit:1.8.0")
}

برای جزئیات بیشتر، مثال WebView در GitHub کاوش کنید.

یک WebView به برنامه خود اضافه کنید

برای افزودن WebView به برنامه خود، می‌توانید عنصر <WebView> را در طرح‌بندی فعالیت خود وارد کنید یا کل پنجره Activity را به عنوان WebView در onCreate() تنظیم کنید.

یک WebView در طرح‌بندی فعالیت اضافه کنید

برای افزودن WebView به برنامه خود در طرح‌بندی، کد زیر را به فایل XML طرح‌بندی فعالیت خود اضافه کنید:

<WebView
    android:id="@+id/webview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
/>

برای بارگذاری یک صفحه وب در WebView ، از loadUrl() استفاده کنید، همانطور که در مثال زیر نشان داده شده است:

کاتلین

val myWebView: WebView = findViewById(R.id.webview)
myWebView.loadUrl("http://www.example.com")

جاوا

WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl("http://www.example.com");

افزودن WebView در onCreate()

برای افزودن WebView به برنامه خود در روش onCreate() یک فعالیت، از منطقی شبیه به زیر استفاده کنید:

کاتلین

val myWebView = WebView(activityContext)
setContentView(myWebView)

جاوا

WebView myWebView = new WebView(activityContext);
setContentView(myWebView);

سپس صفحه را بارگذاری کنید:

کاتلین

myWebView.loadUrl("http://www.example.com")

جاوا

myWebView.loadUrl("https://www.example.com");

یا URL را از یک رشته HTML بارگیری کنید:

کاتلین

// Create an unencoded HTML string, then convert the unencoded HTML string into
// bytes. Encode it with base64 and load the data.
val unencodedHtml =
     "<html><body>'%23' is the percent code for ‘#‘ </body></html>";
val encodedHtml = Base64.encodeToString(unencodedHtml.toByteArray(), Base64.NO_PADDING)
myWebView.loadData(encodedHtml, "text/html", "base64")

جاوا

// Create an unencoded HTML string, then convert the unencoded HTML string into
// bytes. Encode it with base64 and load the data.
String unencodedHtml =
     "<html><body>'%23' is the percent code for ‘#‘ </body></html>";
String encodedHtml = Base64.encodeToString(unencodedHtml.getBytes(),
        Base64.NO_PADDING);
myWebView.loadData(encodedHtml, "text/html", "base64");

برنامه شما باید به اینترنت دسترسی داشته باشد. برای دسترسی به اینترنت، همانطور که در مثال زیر نشان داده شده است، مجوز INTERNET را در فایل مانیفست خود درخواست کنید:

<manifest ... >
    <uses-permission android:name="android.permission.INTERNET" />
    ...
</manifest>

با انجام یکی از موارد زیر می توانید WebView خود را سفارشی کنید:

  • فعال کردن پشتیبانی تمام صفحه با استفاده از WebChromeClient . این کلاس همچنین زمانی فراخوانی می شود که WebView برای تغییر رابط کاربری برنامه میزبان، مانند ایجاد یا بستن پنجره ها یا ارسال گفتگوهای جاوا اسکریپت به کاربر، به مجوز نیاز دارد. برای کسب اطلاعات بیشتر در مورد اشکال زدایی در این زمینه، Debug web apps را بخوانید.
  • مدیریت رویدادهایی که بر رندر محتوا تأثیر می‌گذارند، مانند خطاهایی در ارسال فرم یا پیمایش با استفاده از WebViewClient . شما همچنین می توانید از این زیر کلاس برای جلوگیری از بارگذاری URL استفاده کنید.
  • فعال کردن جاوا اسکریپت با تغییر WebSettings .
  • استفاده از جاوا اسکریپت برای دسترسی به اشیاء چارچوب Android که به WebView تزریق کرده اید.

از جاوا اسکریپت در WebView استفاده کنید

اگر صفحه وبی که می خواهید در WebView خود بارگیری کنید از جاوا اسکریپت استفاده می کند، باید جاوا اسکریپت را برای WebView خود فعال کنید. پس از فعال کردن جاوا اسکریپت، می توانید بین کد برنامه و کد جاوا اسکریپت خود رابط ایجاد کنید.

جاوا اسکریپت را فعال کنید

جاوا اسکریپت در WebView به طور پیش فرض غیرفعال است. می‌توانید آن را از طریق WebSettings متصل به WebView خود فعال کنید. WebSettings با getSettings() بازیابی کنید، سپس جاوا اسکریپت را با setJavaScriptEnabled() فعال کنید.

مثال زیر را ببینید:

کاتلین

val myWebView: WebView = findViewById(R.id.webview)
myWebView.settings.javaScriptEnabled = true

جاوا

WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);

WebSettings دسترسی به تنظیمات مختلفی را فراهم می کند که ممکن است برای شما مفید باشد. به عنوان مثال، اگر در حال توسعه یک برنامه وب هستید که به طور خاص برای WebView در برنامه Android شما طراحی شده است، می توانید یک رشته عامل سفارشی کاربر با setUserAgentString() تعریف کنید، سپس از عامل کاربر سفارشی در صفحه وب خود پرس و جو کنید تا تأیید کنید که مشتری درخواست کننده صفحه وب شما برنامه اندروید شما است.

کد جاوا اسکریپت را به کد اندروید متصل کنید

هنگام توسعه یک برنامه وب که به طور خاص برای WebView در برنامه Android شما طراحی شده است، می توانید رابط هایی بین کد جاوا اسکریپت و کد اندروید سمت سرویس گیرنده ایجاد کنید. به عنوان مثال، کد جاوا اسکریپت شما می تواند به جای استفاده از تابع alert() جاوا اسکریپت، متدی را در کد اندروید شما برای نمایش Dialog فراخوانی کند.

برای اتصال یک رابط جدید بین کد جاوا اسکریپت و کد اندروید، addJavascriptInterface() را فراخوانی کنید و آن را یک نمونه کلاس ارسال کنید تا به جاوا اسکریپت متصل شود و نام رابطی که جاوا اسکریپت شما می تواند برای دسترسی به کلاس فراخوانی کند.

به عنوان مثال، می توانید کلاس زیر را در برنامه اندروید خود قرار دهید:

کاتلین

/** Instantiate the interface and set the context.  */
class WebAppInterface(private val mContext: Context) {

    /** Show a toast from the web page.  */
    @JavascriptInterface
    fun showToast(toast: String) {
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show()
    }
}

جاوا

public class WebAppInterface {
    Context mContext;

    /** Instantiate the interface and set the context. */
    WebAppInterface(Context c) {
        mContext = c;
    }

    /** Show a toast from the web page. */
    @JavascriptInterface
    public void showToast(String toast) {
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
    }
}

در این مثال، کلاس WebAppInterface به صفحه وب اجازه می دهد تا با استفاده از متد showToast() یک پیام Toast ایجاد کند.

می توانید این کلاس را به جاوا اسکریپتی که در WebView شما اجرا می شود با addJavascriptInterface() متصل کنید، همانطور که در مثال زیر نشان داده شده است:

کاتلین

val webView: WebView = findViewById(R.id.webview)
webView.addJavascriptInterface(WebAppInterface(this), "Android")

جاوا

WebView webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new WebAppInterface(this), "Android");

این یک رابط به نام Android برای جاوا اسکریپت در حال اجرا در WebView ایجاد می کند. در این مرحله، برنامه وب شما به کلاس WebAppInterface دسترسی دارد. به عنوان مثال، در اینجا برخی از HTML و جاوا اسکریپت وجود دارد که وقتی کاربر روی دکمه ای ضربه می زند، یک پیام نان تست با استفاده از رابط جدید ایجاد می کند:

<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />

<script type="text/javascript">
    function showAndroidToast(toast) {
        Android.showToast(toast);
    }
</script>

نیازی به مقداردهی اولیه رابط Android از جاوا اسکریپت نیست. WebView به طور خودکار آن را در دسترس صفحه وب شما قرار می دهد. بنابراین، وقتی کاربر روی دکمه ضربه می‌زند، تابع showAndroidToast() از رابط Android برای فراخوانی متد WebAppInterface.showToast() استفاده می‌کند.

ناوبری صفحه را مدیریت کنید

وقتی کاربر روی پیوندی از یک صفحه وب در WebView شما ضربه می‌زند، به‌طور پیش‌فرض، Android برنامه‌ای را راه‌اندازی می‌کند که URL‌ها را مدیریت می‌کند. معمولاً مرورگر وب پیش‌فرض URL مقصد را باز کرده و بارگذاری می‌کند. با این حال، می‌توانید این رفتار را برای WebView خود لغو کنید تا پیوندها در WebView شما باز شوند. سپس می توانید به کاربر اجازه دهید در تاریخچه صفحه وب خود که توسط WebView شما نگهداری می شود به عقب و جلو حرکت کند.

برای باز کردن پیوندهایی که کاربر روی آنها ضربه زده است، با استفاده از setWebViewClient() یک WebViewClient برای WebView خود ارائه دهید. همه پیوندهایی که کاربر روی آنها ضربه می زند در WebView شما بارگیری می شود. اگر می خواهید کنترل بیشتری روی مکان بارگیری پیوند کلیک شده داشته باشید، WebViewClient خود را ایجاد کنید که متد shouldOverrideUrlLoading() لغو می کند. مثال زیر فرض می‌کند که MyWebViewClient یک کلاس داخلی از Activity است.

کاتلین

private class MyWebViewClient : WebViewClient() {

    override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
        if (Uri.parse(url).host == "www.example.com") {
            // This is your website, so don't override. Let your WebView load
            // the page.
            return false
        }
        // Otherwise, the link isn't for a page on your site, so launch another
        // Activity that handles URLs.
        Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply {
            startActivity(this)
        }
        return true
    }
}

جاوا

private class MyWebViewClient extends WebViewClient {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        if ("www.example.com".equals(request.getUrl().getHost())) {
      // This is your website, so don't override. Let your WebView load the
      // page.
      return false;
    }
    // Otherwise, the link isn't for a page on your site, so launch another
    // Activity that handles URLs.
    Intent intent = new Intent(Intent.ACTION_VIEW, request.getUrl());
    startActivity(intent);
    return true;
  }
}

سپس یک نمونه از این WebViewClient جدید برای WebView ایجاد کنید:

کاتلین

val myWebView: WebView = findViewById(R.id.webview)
myWebView.webViewClient = MyWebViewClient()

جاوا

WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new MyWebViewClient());

اکنون وقتی کاربر روی یک پیوند ضربه می‌زند، سیستم متد shouldOverrideUrlLoading() را فراخوانی می‌کند که بررسی می‌کند آیا میزبان URL با یک دامنه خاص مطابقت دارد، همانطور که در مثال قبل تعریف شد. اگر مطابقت داشت، متد false را برمی‌گرداند و بارگذاری URL را لغو نمی‌کند. به WebView اجازه می‌دهد URL را طبق معمول بارگیری کند. اگر میزبان URL مطابقت نداشته باشد، یک Intent برای راه اندازی Activity پیش فرض برای مدیریت URL ها ایجاد می شود که به مرورگر وب پیش فرض کاربر حل می شود.

مدیریت URL های سفارشی

WebView هنگام درخواست منابع و حل و فصل پیوندهایی که از یک طرح URL سفارشی استفاده می کنند، محدودیت هایی اعمال می کند. به عنوان مثال، اگر callbackهایی مانند shouldOverrideUrlLoading() یا shouldInterceptRequest() را پیاده سازی کنید، WebView آنها را فقط برای URL های معتبر فراخوانی می کند.

برای مثال، WebView ممکن است متد shouldOverrideUrlLoading() شما را برای پیوندهایی مانند این فراخوانی نکند:

<a href="showProfile">Show Profile</a>

نشانی‌های وب نامعتبر، مانند نمونه‌ای که در مثال قبل نشان داده شد، در WebView به‌صورت متناقض مدیریت می‌شوند، بنابراین توصیه می‌کنیم به جای آن از یک URL با شکل‌دهی مناسب استفاده کنید. می توانید از یک طرح سفارشی یا یک URL HTTPS برای دامنه ای که سازمان شما کنترل می کند استفاده کنید.

به جای استفاده از یک رشته ساده در یک پیوند، مانند مثال قبلی، می توانید از یک طرح سفارشی مانند زیر استفاده کنید:

<a href="example-app:showProfile">Show Profile</a>

سپس می توانید این URL را در متد shouldOverrideUrlLoading() خود به این صورت مدیریت کنید:

کاتلین

// The URL scheme must be non-hierarchical, meaning no trailing slashes.
const val APP_SCHEME = "example-app:"

override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
    return if (url?.startsWith(APP_SCHEME) == true) {
        urlData = URLDecoder.decode(url.substring(APP_SCHEME.length), "UTF-8")
        respondToData(urlData)
        true
    } else {
        false
    }
}

جاوا

// The URL scheme must be non-hierarchical, meaning no trailing slashes.
private static final String APP_SCHEME = "example-app:";

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    if (url.startsWith(APP_SCHEME)) {
        urlData = URLDecoder.decode(url.substring(APP_SCHEME.length()), "UTF-8");
        respondToData(urlData);
        return true;
    }
    return false;
}

API shouldOverrideUrlLoading() اساساً برای راه‌اندازی intent برای URL‌های خاص در نظر گرفته شده است. هنگام اجرای آن، مطمئن شوید که برای URL هایی که WebView کنترل می کند، false برگردانید. با این حال، شما محدود به راه اندازی intent نیستید. می‌توانید intent راه‌اندازی را با هر رفتار سفارشی در نمونه‌های کد قبلی جایگزین کنید.

هنگامی که WebView شما بارگذاری URL را لغو می کند، به طور خودکار تاریخچه ای از صفحات وب بازدید شده را جمع آوری می کند. با goBack() و goForward() می توانید در تاریخچه به عقب و جلو حرکت کنید.

برای مثال، موارد زیر نشان می‌دهد که چگونه Activity شما می‌تواند از دکمه برگشت دستگاه برای پیمایش به عقب استفاده کند:

کاتلین

override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
    // Check whether the key event is the Back button and if there's history.
    if (keyCode == KeyEvent.KEYCODE_BACK && myWebView.canGoBack()) {
        myWebView.goBack()
        return true
    }
    // If it isn't the Back button or there isn't web page history, bubble up to
    // the default system behavior. Probably exit the activity.
    return super.onKeyDown(keyCode, event)
}

جاوا

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    // Check whether the key event is the Back button and if there's history.
    if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) {
        myWebView.goBack();
        return true;
    }
    // If it isn't the Back button or there's no web page history, bubble up to
    // the default system behavior. Probably exit the activity.
    return super.onKeyDown(keyCode, event);
}

اگر برنامه از AndroidX AppCompat 1.6.0 و بالاتر استفاده می کند، می توانید قطعه قبلی را حتی بیشتر ساده کنید:

کاتلین

onBackPressedDispatcher.addCallback {
    // Check whether there's history.
    if (myWebView.canGoBack()) {
        myWebView.goBack()
    }
}

جاوا

onBackPressedDispatcher.addCallback {
    // Check whether there's history.
    if (myWebView.canGoBack()) {
        myWebView.goBack();
    }
}

اگر تاریخچه صفحه وب برای بازدید کاربر وجود داشته باشد، متد canGoBack() true را برمی گرداند. به همین ترتیب، می‌توانید از canGoForward() برای بررسی اینکه آیا تاریخچه فوروارد وجود دارد یا خیر استفاده کنید. اگر این بررسی را انجام ندهید، پس از اینکه کاربر به پایان تاریخچه رسید، goBack() و goForward() هیچ کاری انجام نمی دهند.

کنترل تغییرات پیکربندی دستگاه

در طول زمان اجرا، هنگامی که پیکربندی دستگاه تغییر می کند، تغییرات وضعیت فعالیت رخ می دهد، مانند زمانی که کاربران دستگاه را می چرخانند یا ویرایشگر روش ورودی (IME) را رد می کنند. این تغییرات باعث از بین رفتن اکتیویتی یک آبجکت WebView و ایجاد یک اکتیویتی جدید می شود که همچنین یک آبجکت WebView جدید ایجاد می کند که URL شیء تخریب شده را بارگذاری می کند. برای تغییر رفتار پیش‌فرض فعالیت خود، می‌توانید نحوه مدیریت تغییرات orientation در مانیفست خود را تغییر دهید. برای کسب اطلاعات بیشتر در مورد مدیریت تغییرات پیکربندی در زمان اجرا، Handle configuration changes را بخوانید.

ویندوز را مدیریت کنید

به‌طور پیش‌فرض، درخواست‌ها برای باز کردن پنجره‌های جدید نادیده گرفته می‌شوند. این درست است چه آنها با جاوا اسکریپت باز شوند و چه توسط ویژگی هدف در یک پیوند. می‌توانید WebChromeClient خود را سفارشی کنید تا رفتار خود را برای باز کردن چندین پنجره ارائه دهد.

برای ایمن نگه داشتن برنامه خود، بهتر است از باز شدن پنجره های بازشو و جدید جلوگیری کنید. امن‌ترین راه برای پیاده‌سازی این رفتار این است که "true" به setSupportMultipleWindows() منتقل کنید، اما متد onCreateWindow() را که setSupportMultipleWindows() به آن بستگی دارد لغو نکنید. این منطق از بارگذاری هر صفحه ای که از target="_blank" در لینک های خود استفاده می کند جلوگیری می کند.