将 CSS 注入 android 中带有 webview 的站点
inject CSS to a site with webview in android
例如,我想将 www.google.com
的背景颜色更改为 red
。
我用过webview
,我的style.css
文件在assest folder
。我想将这个 style.css
文件注入到 www.google.com
。我的代码有什么问题?请为我写出正确的代码。谢谢。
我的 MainActitviy.java
文件:
package com.example.mysina;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.webkit.WebView;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView webView = new WebView(this);
setContentView(webView);
String html = "<html><head><style> src: url('file:///android_asset/style.css')</style></head></html>";
webView.loadData(html, "text/html", "utf-8");
webView.loadUrl("https://www.google.com");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
您不能直接注入 CSS,但是您可以使用 Javascript 来操作页面 dom。
public class MainActivity extends ActionBarActivity {
WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
webView = new WebView(this);
setContentView(webView);
// Enable Javascript
webView.getSettings().setJavaScriptEnabled(true);
// Add a WebViewClient
webView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
// Inject CSS when page is done loading
injectCSS();
super.onPageFinished(view, url);
}
});
// Load a webpage
webView.loadUrl("https://www.google.com");
}
// Inject CSS method: read style.css from assets folder
// Append stylesheet to document head
private void injectCSS() {
try {
InputStream inputStream = getAssets().open("style.css");
byte[] buffer = new byte[inputStream.available()];
inputStream.read(buffer);
inputStream.close();
String encoded = Base64.encodeToString(buffer, Base64.NO_WRAP);
webView.loadUrl("javascript:(function() {" +
"var parent = document.getElementsByTagName('head').item(0);" +
"var style = document.createElement('style');" +
"style.type = 'text/css';" +
// Tell the browser to BASE64-decode the string into your script !!!
"style.innerHTML = window.atob('" + encoded + "');" +
"parent.appendChild(style)" +
"})()");
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
对于 Kotlin 用户
导入这个
import android.util.Base64
这是 onPageFinished 代码
override fun onPageFinished(view: WebView?, url: String?) {
injectCSS()
}
这是要调用的代码
private fun injectCSS() {
try {
val inputStream = assets.open("style.css")
val buffer = ByteArray(inputStream.available())
inputStream.read(buffer)
inputStream.close()
val encoded = Base64.encodeToString(buffer , Base64.NO_WRAP)
webframe.loadUrl(
"javascript:(function() {" +
"var parent = document.getElementsByTagName('head').item(0);" +
"var style = document.createElement('style');" +
"style.type = 'text/css';" +
// Tell the browser to BASE64-decode the string into your script !!!
"style.innerHTML = window.atob('" + encoded + "');" +
"parent.appendChild(style)" +
"})()"
)
} catch (e: Exception) {
e.printStackTrace()
}
}
实际上,您可以在 API 11+ 上使用 WebViewClient.shouldInterceptRequest
。示例:webview shouldinterceptrequest example
我能够通过使用在 API 19 https://developer.android.com/reference/android/webkit/WebView
中添加到 WebView 的“evaluateJavascript”注入 css
Kotlin 中的示例:
private lateinit var webView: WebView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//...
webView = findViewById(R.id.your_webview_name)
webView.settings.javaScriptEnabled = true
webView.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView, url: String) {
val css = ".menu_height{height:35px;}.. etc..." //your css as String
val js = "var style = document.createElement('style'); style.innerHTML = '$css'; document.head.appendChild(style);"
webView.evaluateJavascript(js,null)
super.onPageFinished(view, url)
}
}
webView.loadUrl("https://mywepage.com") //webpage you want to load
}
更新: 上面的代码在应用所有注入的 CSS 时出现问题。在咨询了我的 Web 开发人员之后,我们决定将 link 注入到 CSS 文件而不是 CSS 代码本身。我更改了 css 和 js 变量的值 ->
val css = "https://mywebsite.com/css/custom_app_styles.css"
val js = "var link = document.createElement('link'); link.setAttribute('href','$css'); link.setAttribute('rel', 'stylesheet'); link.setAttribute('type','text/css'); document.head.appendChild(link);"
这是在 Kotlin 中使用 Manish 解决方案的代码片段 UI/UX 改进 以 避免 webview blinking/flash 注入时 css
第 1 步:定义编码为 Base64
的 css 样式
companion object {
private const val injectCss = """
Your CSS Style Go HERE
"""
private val styleCss =
"""
javascript:(function() {
var parent = document.getElementsByTagName('head').item(0);
var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = window.atob('${stringToBase64(hideHeaderCss)}');
parent.appendChild(style)
})()
"""
private fun stringToBase64(input: String): String {
val inputStream: InputStream = ByteArrayInputStream(input.toByteArray(StandardCharsets.UTF_8))
val buffer = ByteArray(inputStream.available())
inputStream.read(buffer)
inputStream.close()
return android.util.Base64.encodeToString(buffer, android.util.Base64.NO_WRAP)
}
}
第 2 步:您的 webview 初始化状态应该是不可见的
<WebView
android:id="@+id/wv_content"
android:visibility="invisible"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
步骤 3: 加载 webview 注入 css, 这里的技巧是只在加载完成时显示 webview
@SuppressLint("SetJavaScriptEnabled")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewDataBinding.wvContent.loadUrl("Your URL Go Here")
viewDataBinding.wvContent.settings.javaScriptEnabled = true
viewDataBinding.wvContent.webViewClient = object : WebViewClient() {
override fun onPageCommitVisible(view: WebView?, url: String?) {
applyContentWithCSS()
super.onPageCommitVisible(view, url)
}
override fun onPageFinished(view: WebView?, url: String?) {
applyContentWithCSS()
//Only show when load complete
if (viewDataBinding.wvContent.progress == 100) {
viewDataBinding.wvContent.smoothShow()
}
super.onPageFinished(view, url)
}
}
}
第 4 步:通过平滑过渡来改善用户体验以显示 webview
fun View.smoothShow() {
this.apply {
alpha = 0f
visibility = View.VISIBLE
animate()
.alpha(1f)
.setDuration(300)
.setListener(null)
}
}
例如,我想将 www.google.com
的背景颜色更改为 red
。
我用过webview
,我的style.css
文件在assest folder
。我想将这个 style.css
文件注入到 www.google.com
。我的代码有什么问题?请为我写出正确的代码。谢谢。
我的 MainActitviy.java
文件:
package com.example.mysina;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.webkit.WebView;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView webView = new WebView(this);
setContentView(webView);
String html = "<html><head><style> src: url('file:///android_asset/style.css')</style></head></html>";
webView.loadData(html, "text/html", "utf-8");
webView.loadUrl("https://www.google.com");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
您不能直接注入 CSS,但是您可以使用 Javascript 来操作页面 dom。
public class MainActivity extends ActionBarActivity {
WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
webView = new WebView(this);
setContentView(webView);
// Enable Javascript
webView.getSettings().setJavaScriptEnabled(true);
// Add a WebViewClient
webView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
// Inject CSS when page is done loading
injectCSS();
super.onPageFinished(view, url);
}
});
// Load a webpage
webView.loadUrl("https://www.google.com");
}
// Inject CSS method: read style.css from assets folder
// Append stylesheet to document head
private void injectCSS() {
try {
InputStream inputStream = getAssets().open("style.css");
byte[] buffer = new byte[inputStream.available()];
inputStream.read(buffer);
inputStream.close();
String encoded = Base64.encodeToString(buffer, Base64.NO_WRAP);
webView.loadUrl("javascript:(function() {" +
"var parent = document.getElementsByTagName('head').item(0);" +
"var style = document.createElement('style');" +
"style.type = 'text/css';" +
// Tell the browser to BASE64-decode the string into your script !!!
"style.innerHTML = window.atob('" + encoded + "');" +
"parent.appendChild(style)" +
"})()");
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
对于 Kotlin 用户
导入这个
import android.util.Base64
这是 onPageFinished 代码
override fun onPageFinished(view: WebView?, url: String?) {
injectCSS()
}
这是要调用的代码
private fun injectCSS() {
try {
val inputStream = assets.open("style.css")
val buffer = ByteArray(inputStream.available())
inputStream.read(buffer)
inputStream.close()
val encoded = Base64.encodeToString(buffer , Base64.NO_WRAP)
webframe.loadUrl(
"javascript:(function() {" +
"var parent = document.getElementsByTagName('head').item(0);" +
"var style = document.createElement('style');" +
"style.type = 'text/css';" +
// Tell the browser to BASE64-decode the string into your script !!!
"style.innerHTML = window.atob('" + encoded + "');" +
"parent.appendChild(style)" +
"})()"
)
} catch (e: Exception) {
e.printStackTrace()
}
}
实际上,您可以在 API 11+ 上使用 WebViewClient.shouldInterceptRequest
。示例:webview shouldinterceptrequest example
我能够通过使用在 API 19 https://developer.android.com/reference/android/webkit/WebView
中添加到 WebView 的“evaluateJavascript”注入 cssKotlin 中的示例:
private lateinit var webView: WebView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//...
webView = findViewById(R.id.your_webview_name)
webView.settings.javaScriptEnabled = true
webView.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView, url: String) {
val css = ".menu_height{height:35px;}.. etc..." //your css as String
val js = "var style = document.createElement('style'); style.innerHTML = '$css'; document.head.appendChild(style);"
webView.evaluateJavascript(js,null)
super.onPageFinished(view, url)
}
}
webView.loadUrl("https://mywepage.com") //webpage you want to load
}
更新: 上面的代码在应用所有注入的 CSS 时出现问题。在咨询了我的 Web 开发人员之后,我们决定将 link 注入到 CSS 文件而不是 CSS 代码本身。我更改了 css 和 js 变量的值 ->
val css = "https://mywebsite.com/css/custom_app_styles.css"
val js = "var link = document.createElement('link'); link.setAttribute('href','$css'); link.setAttribute('rel', 'stylesheet'); link.setAttribute('type','text/css'); document.head.appendChild(link);"
这是在 Kotlin 中使用 Manish 解决方案的代码片段 UI/UX 改进 以 避免 webview blinking/flash 注入时 css
第 1 步:定义编码为 Base64
的 css 样式 companion object {
private const val injectCss = """
Your CSS Style Go HERE
"""
private val styleCss =
"""
javascript:(function() {
var parent = document.getElementsByTagName('head').item(0);
var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = window.atob('${stringToBase64(hideHeaderCss)}');
parent.appendChild(style)
})()
"""
private fun stringToBase64(input: String): String {
val inputStream: InputStream = ByteArrayInputStream(input.toByteArray(StandardCharsets.UTF_8))
val buffer = ByteArray(inputStream.available())
inputStream.read(buffer)
inputStream.close()
return android.util.Base64.encodeToString(buffer, android.util.Base64.NO_WRAP)
}
}
第 2 步:您的 webview 初始化状态应该是不可见的
<WebView
android:id="@+id/wv_content"
android:visibility="invisible"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
步骤 3: 加载 webview 注入 css, 这里的技巧是只在加载完成时显示 webview
@SuppressLint("SetJavaScriptEnabled")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewDataBinding.wvContent.loadUrl("Your URL Go Here")
viewDataBinding.wvContent.settings.javaScriptEnabled = true
viewDataBinding.wvContent.webViewClient = object : WebViewClient() {
override fun onPageCommitVisible(view: WebView?, url: String?) {
applyContentWithCSS()
super.onPageCommitVisible(view, url)
}
override fun onPageFinished(view: WebView?, url: String?) {
applyContentWithCSS()
//Only show when load complete
if (viewDataBinding.wvContent.progress == 100) {
viewDataBinding.wvContent.smoothShow()
}
super.onPageFinished(view, url)
}
}
}
第 4 步:通过平滑过渡来改善用户体验以显示 webview
fun View.smoothShow() {
this.apply {
alpha = 0f
visibility = View.VISIBLE
animate()
.alpha(1f)
.setDuration(300)
.setListener(null)
}
}