1 /* 2 * Copyright 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.example.androidx.webkit; 17 18 import static androidx.webkit.WebViewAssetLoader.AssetsPathHandler; 19 20 import android.annotation.SuppressLint; 21 import android.app.Activity; 22 import android.net.Uri; 23 import android.os.Bundle; 24 import android.view.View; 25 import android.webkit.WebResourceRequest; 26 import android.webkit.WebResourceResponse; 27 import android.webkit.WebView; 28 import android.webkit.WebViewClient; 29 import android.widget.Button; 30 31 import androidx.appcompat.app.AppCompatActivity; 32 import androidx.webkit.JavaScriptReplyProxy; 33 import androidx.webkit.WebMessageCompat; 34 import androidx.webkit.WebViewAssetLoader; 35 import androidx.webkit.WebViewCompat; 36 import androidx.webkit.WebViewFeature; 37 38 import org.jspecify.annotations.NonNull; 39 import org.jspecify.annotations.Nullable; 40 41 import java.util.Collections; 42 import java.util.HashSet; 43 44 /** 45 * An {@link Activity} to exercise 46 * {@link WebViewCompat#addDocumentStartJavaScript(WebView, String, java.util.Set)} related 47 * functionality. 48 */ 49 public class DocumentStartJavaScriptActivity extends AppCompatActivity { 50 private final Uri mExampleUri = new Uri.Builder() 51 .scheme("https") 52 .authority("example.com") 53 .appendPath("androidx_webkit") 54 .appendPath("example") 55 .appendPath("assets") 56 .build(); 57 58 private static class MyWebViewClient extends WebViewClient { 59 private final WebViewAssetLoader mAssetLoader; 60 MyWebViewClient(WebViewAssetLoader loader)61 MyWebViewClient(WebViewAssetLoader loader) { 62 mAssetLoader = loader; 63 } 64 65 @Override shouldInterceptRequest(WebView view, WebResourceRequest request)66 public WebResourceResponse shouldInterceptRequest(WebView view, 67 WebResourceRequest request) { 68 return mAssetLoader.shouldInterceptRequest(request.getUrl()); 69 } 70 71 @Override 72 @SuppressWarnings("deprecation") // use the old one for compatibility with all API levels. shouldInterceptRequest(WebView view, String url)73 public WebResourceResponse shouldInterceptRequest(WebView view, String url) { 74 return mAssetLoader.shouldInterceptRequest(Uri.parse(url)); 75 } 76 } 77 78 private static class ReplyMessageListener implements WebViewCompat.WebMessageListener { 79 private JavaScriptReplyProxy mReplyProxy; 80 ReplyMessageListener(Button button)81 ReplyMessageListener(Button button) { 82 button.setOnClickListener((View v) -> { 83 if (mReplyProxy == null) return; 84 mReplyProxy.postMessage("ReplyProxy button clicked."); 85 }); 86 } 87 88 @Override onPostMessage(@onNull WebView view, WebMessageCompat message, @NonNull Uri sourceOrigin, boolean isMainFrame, @NonNull JavaScriptReplyProxy replyProxy)89 public void onPostMessage(@NonNull WebView view, WebMessageCompat message, 90 @NonNull Uri sourceOrigin, 91 boolean isMainFrame, @NonNull JavaScriptReplyProxy replyProxy) { 92 if ("initialization".equals(message.getData())) { 93 mReplyProxy = replyProxy; 94 } 95 } 96 } 97 98 @SuppressLint("SetJavascriptEnabled") 99 @Override onCreate(@ullable Bundle savedInstanceState)100 protected void onCreate(@Nullable Bundle savedInstanceState) { 101 super.onCreate(savedInstanceState); 102 setContentView(R.layout.activity_document_start_javascript); 103 setTitle(R.string.document_start_javascript_activity_title); 104 WebkitHelpers.appendWebViewVersionToTitle(this); 105 106 if (!WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { 107 WebkitHelpers.showMessageInActivity( 108 DocumentStartJavaScriptActivity.this, R.string.webkit_api_not_available); 109 return; 110 } 111 112 // Use WebViewAssetLoader to load html page from app's assets. 113 WebViewAssetLoader assetLoader = 114 new WebViewAssetLoader.Builder() 115 .setDomain("example.com") 116 .addPathHandler(mExampleUri.getPath() + "/", new AssetsPathHandler(this)) 117 .build(); 118 119 Button replyProxyButton = findViewById(R.id.button_reply_proxy); 120 121 WebView webView = findViewById(R.id.webview); 122 webView.setWebViewClient(new MyWebViewClient(assetLoader)); 123 webView.getSettings().setJavaScriptEnabled(true); 124 125 HashSet<String> allowedOriginRules = new HashSet<>( 126 Collections.singletonList("https://example.com")); 127 // Add WebMessageListeners. 128 WebViewCompat.addWebMessageListener(webView, "replyObject", allowedOriginRules, 129 new ReplyMessageListener(replyProxyButton)); 130 final String jsCode = "replyObject.onmessage = function(event) {" 131 + " document.getElementById('result').innerHTML = event.data;" 132 + "};" 133 + "replyObject.postMessage('initialization');"; 134 WebViewCompat.addDocumentStartJavaScript(webView, jsCode, allowedOriginRules); 135 webView.loadUrl( 136 Uri.withAppendedPath(mExampleUri, "www/document_start_javascript.html").toString()); 137 } 138 } 139