【问题标题】:inject CSS to a site with webview in android在android中将CSS注入带有webview的站点
【发布时间】:2015-07-13 03:42:42
【问题描述】:

例如我想将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);
        }
    }

【问题讨论】:

  • 我做的和你做的一样。告诉我你在你的 android 项目中添加 css 的位置,以及你的 css 文件包含什么?我被困住了。请帮忙。

标签: android css webview webkit


【解决方案1】:

您不能直接注入 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);
  }
}

【讨论】:

  • 谢谢。我已将这些代码复制到我的项目中。现在我可以更改页面的样式。但是有一个大问题。它无法加载页面。它说:网页不可用。它不会打开 www.google.com 。我应该更改哪个代码?
  • 这是我在这个主题上看到的最好的答案之一,但请注意,如果您切换样式,会有一点页面跳转。明智的做法是在 CSS 注入完成之前不显示内容。
  • 在 webview 中加载 Url 之前使用 DOM 操作。通过这样做,您可以在运行时注入任何脚本或 javascript 文件,然后将内容加载到 webview。我一直在我的 ePub 播放器中这样做,它就像魅力一样工作。
  • @Vishal 你介意在这里添加一个你在说什么的答案吗?
  • 为什么是 base64 部分?
【解决方案2】:

我能够通过使用“evaluateJavascript”来注入 css,它在 API 19 https://developer.android.com/reference/android/webkit/WebView中添加到 WebView@

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 开发人员协商后,我们决定将 链接 注入 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);"

【讨论】:

    【解决方案3】:

    这里是在 Kotlin 中使用 Manish 解决方案的代码 sn-p,其中有一点 UI/UX 改进在注入 css 时避免 webview 闪烁/闪烁

    第 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 步:使用注入的 css 加载 webview,这里的技巧是仅在加载完成时显示 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 步:通过平滑过渡以显示 web 视图来改进用户体验

    fun View.smoothShow() {
        this.apply {
            alpha = 0f
            visibility = View.VISIBLE
    
            animate()
                .alpha(1f)
                .setDuration(300)
                .setListener(null)
        }
    }
    

    【讨论】:

    • 感谢您提供防止眨眼的提示,并为用户提供更好的无缝体验。
    • 我注意到在onPageStarted 处理程序中插入applyContentWithCSS 会使页面显示在较新的Android 版本上不会闪烁并且不需要动画。
    【解决方案4】:

    对于 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()
                }
    
            }
    

    【讨论】:

      【解决方案5】:

      实际上,您可以在 API 11+ 上使用 WebViewClient.shouldInterceptRequest。示例:webview shouldinterceptrequest example

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-04-09
        • 1970-01-01
        • 2023-04-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-13
        相关资源
        最近更新 更多