Android WebView และ loadData


105

เป็นไปได้ที่จะใช้วิธีการต่อไปนี้สำหรับการตั้งค่าเนื้อหาของ loadData มุมมองเว็บ (ข้อมูลสตริง, สตริง mimeType, การเข้ารหัสสตริง)

จะจัดการปัญหากับการเข้ารหัสข้อมูล html ที่ไม่รู้จักได้อย่างไร!

มีรายการเข้ารหัสหรือไม่!

ฉันรู้จากวิทยาลัยว่าในกรณีของฉัน html มาจาก DB และเข้ารหัสด้วย latin-1 ฉันพยายามตั้งค่าพารามิเตอร์การเข้ารหัสเป็น latin-1 เป็น ISO-8859-1 / iso-8859-1 แต่ยังมีปัญหากับการแสดงสัญญาณพิเศษเช่นä, ö, ü

ฉันจะขอบคุณมากสำหรับคำแนะนำใด ๆ

คำตอบ:


207
myWebView.loadData(myHtmlString, "text/html; charset=UTF-8", null);

สิ่งนี้ทำงานได้อย่างไม่มีที่ติโดยเฉพาะบน Android 4.0 ซึ่งเห็นได้ชัดว่าไม่สนใจการเข้ารหัสอักขระภายใน HTML

ทดสอบบน 2.3 และ 4.0.3

อันที่จริงฉันไม่รู้ว่าค่าอื่น ๆ นอกจาก "base64" ใช้พารามิเตอร์สุดท้ายอย่างไร บางตัวอย่างของ Google ใส่ค่าว่างไว้ที่นั่น


2
สิ่งนี้ไม่สามารถทำงานได้อย่าง "ไม่มีที่ติ" หากคุณมีอักขระนอกชุดอักขระ US-ASCII
Andrey Novikov

1
เพิ่งลองใช้อุปกรณ์ 4.2.2 และใช้งานได้เหมือนมีเสน่ห์ แต่บนอุปกรณ์ 2.3.6 จะแสดงอักขระขยะเหมือนกัน : S
Frank

สิ่งนี้ใช้ได้กับฉันใน 4.1.2 (ซึ่งไม่สนใจชุดอักขระภายใน HTML) และด้วยการเข้ารหัส Latin1! ไปคิด
Luis A. Florit

2
@ Frank Same ที่นี่ทดสอบกับ HTC one 2.3.7 (อาจเป็นขนมปังขิงทั้งหมด) และมีขยะเหมือนกันฉันต้องใช้โซลูชัน Andrey Novikov ด้วยWebView.loadDataWithBaseURL()
ForceMagic

อะไรคือความแตกต่างระหว่างคำตอบของคุณและ myWebView.loadData (myHtmlString, "text / html", "UTF-8");
Lou Morda

135

WebView.loadData () ทำงานไม่ถูกต้องเลย สิ่งที่ฉันต้องทำคือ:

String header = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>";
myWebView.loadData(header+myHtmlString, "text/html", "UTF-8");

ฉันคิดว่าในกรณีของคุณคุณควรแทนที่ UTF-8 ด้วย latin1 หรือ ISO-8859-1 ทั้งในส่วนหัวและใน WebView.loadData ()

และเพื่อให้คำตอบแบบเต็มนี่คือรายการการเข้ารหัสอย่างเป็นทางการ: http://www.iana.org/assignments/character-sets

ฉันอัปเดตคำตอบให้ครอบคลุมมากขึ้น:

ในการใช้WebView.loadData ()กับการเข้ารหัสที่ไม่ใช่ latin1 คุณต้องเข้ารหัสเนื้อหา html ตัวอย่างก่อนหน้าทำงานไม่ถูกต้องใน Android 4+ ดังนั้นฉันจึงแก้ไขให้มีลักษณะดังนี้:

WebSettings settings = myWebView.getSettings();
settings.setDefaultTextEncodingName("utf-8");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
    String base64 = Base64.encodeToString(htmlString.getBytes(), Base64.DEFAULT);
    myWebView.loadData(base64, "text/html; charset=utf-8", "base64");
} else {
    String header = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>";
    myWebView.loadData(header + htmlString, "text/html; charset=UTF-8", null);

}

แต่ต่อมาฉันได้เปลี่ยนเป็นWebView.loadDataWithBaseURL ()และรหัสก็สะอาดมากและไม่ขึ้นอยู่กับเวอร์ชัน Android:

WebSettings settings = myWebView.getSettings();
settings.setDefaultTextEncodingName("utf-8");
myWebView.loadDataWithBaseURL(null, htmlString, "text/html", "utf-8", null);

ด้วยเหตุผลบางประการฟังก์ชันเหล่านี้มีการใช้งานที่แตกต่างกันอย่างสิ้นเชิง


1
Privet, Andrey ฉันได้ลองวิธีแก้ปัญหาของคุณแล้ว น่าเสียดายที่มันไม่ได้ผลสำหรับฉัน :(
Tima

คุณลอง UTF-8 ตามที่อธิบายไว้หรือไม่? ตอนนี้เมื่อฉันคิดถึงคำถามของคุณมันเกิดขึ้นกับฉันว่าใน Java สตริงทั้งหมดอยู่ใน UTF-8 ดังนั้นตัวอย่างของฉันควรใช้งานได้เหมือนเดิม
Andrey Novikov

สตริงทั้งหมดเป็น UTF-8 แต่ข้อความที่มาจากเซิร์ฟเวอร์เป็นภาษาละติน -1 ฉันคิดว่าฉันลองใช้ UTF-8 กับ latin-1 และ ISO-8859-1 แต่ก็ยังเห็นสัญญาณแปลก ๆ แทนที่จะเป็นü, ö, ä แต่ฉันมีความคิดอีกอย่างฉันจะพยายามแปลงไบต์สตรีมจากเซิร์ฟเวอร์เป็นสตริงโดยใช้การเข้ารหัสที่ถูกต้อง บางทีนั่นอาจช่วยฉันได้
Tima

4
ในการเข้ารหัส 4.0+ ควรตั้งค่าเป็นประเภท mime ด้วยเช่นกัน "text / html; chartset = utf-8" มิฉะนั้นจะไม่รู้จัก
marwinXXII

2
ตัวอย่างสุดท้าย (อันที่มี loadDataWithBaseURL) ใช้งานได้ดีทั้งบนอุปกรณ์ 4.2.2 และ 2.3.6: D
Frank

36

ตามที่ฉันเข้าใจloadData()เพียงสร้างdata:URL พร้อมข้อมูลที่ระบุ

อ่านJavadocsสำหรับloadData():

หากค่าของพารามิเตอร์การเข้ารหัสคือ 'base64' ข้อมูลจะต้องถูกเข้ารหัสเป็น base64 มิฉะนั้นข้อมูลจะต้องใช้การเข้ารหัส ASCII สำหรับอ็อกเต็ตภายในช่วงของอักขระ URL ที่ปลอดภัยและใช้การเข้ารหัสมาตรฐาน% xx hex ของ URL สำหรับอ็อกเต็ตนอกช่วงนั้น ตัวอย่างเช่น, '#', '%', '\', '?' ควรแทนที่ด้วย% 23,% 25,% 27,% 3f ตามลำดับ

URL โครงร่าง 'data' ที่สร้างโดยวิธีนี้ใช้ชุดอักขระ US-ASCII เริ่มต้น หากคุณต้องการตั้งค่าชุดอักขระอื่นคุณควรสร้าง URL แบบแผน 'data' ซึ่งระบุพารามิเตอร์ชุดอักขระอย่างชัดเจนในส่วน mediatype ของ URL และเรียก loadUrl (String) แทน โปรดทราบว่าชุดอักขระที่ได้รับจากส่วน mediatype ของ URL ข้อมูลจะลบล้างสิ่งที่ระบุในเอกสาร HTML หรือ XML เสมอ

ดังนั้นคุณควรใช้ US-ASCII และหลีกเลี่ยงอักขระพิเศษใด ๆ ด้วยตัวคุณเองหรือเพียงแค่เข้ารหัสทุกอย่างโดยใช้ Base64 สิ่งต่อไปนี้ควรใช้งานได้โดยสมมติว่าคุณใช้ UTF-8 (ฉันยังไม่ได้ทดสอบกับ latin1):

String data = ...;  // the html data
String base64 = android.util.Base64.encodeToString(data.getBytes("UTF-8"), android.util.Base64.DEFAULT);
webView.loadData(base64, "text/html; charset=utf-8", "base64");

นี่เตือนให้ฉันตรวจสอบเอกสารก่อนที่จะเดินไปทุกที่
Pradeep

ขอบคุณสำหรับคำตอบ! กำลังโหลดวิธีใช้ HTML ที่สร้างขึ้นในบริบทต่างๆในมุมมองเว็บและใช้งานได้เพียงบางครั้งเท่านั้น สิ่งนี้ได้รับการแก้ไขแล้ว
eric

20

ฉันมีปัญหานี้ แต่:

String content = "<html><head><meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" /></head><body>";
content += mydata + "</body></html>";
WebView1.loadData(content, "text/html", "UTF-8");

ใช้ไม่ได้กับอุปกรณ์ทั้งหมด และฉันรวมวิธีการบางอย่าง:

String content = 
       "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"+
       "<html><head>"+
       "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />"+
       "</head><body>";

content += myContent + "</body></html>";

WebView WebView1 = (WebView) findViewById(R.id.webView1);
WebView1.loadData(content, "text/html; charset=utf-8", "UTF-8");

มันได้ผล.


นี่ไม่ใช่สิ่งที่ Google แนะนำ ดูคำตอบของฉันและตรวจสอบวิดีโอพูดคุย ;-) stackoverflow.com/questions/3961589/…
Pascal

7

ใช้สิ่งนี้: String customHtml = text;

           wb.loadDataWithBaseURL(null,customHtml,"text/html", "UTF-8", null);

15 โพสต์ในภายหลังและนี่เป็นสิ่งเดียวที่เหมาะกับฉัน
Guy Cothal

5
 String strWebData="html...." //**Your html string**

 WebView webDetail=(WebView) findViewById(R.id.webView1);

 WebSettings websetting = webDetail.getSettings();

 websetting.setDefaultTextEncodingName("utf-8");

 webDetail.loadData(strWebData, "text/html; charset=utf-8", null);

5

ปลอดภัยที่สุดวิธีการโหลด htmlContent ในมุมมองของเว็บคือ:

  1. ใช้การเข้ารหัส base64 (คำแนะนำอย่างเป็นทางการ)
  2. ระบุ UFT-8 สำหรับประเภทเนื้อหา html เช่น "text / html; charset = utf-8" แทน "text / html" (คำแนะนำส่วนตัว)

"การเข้ารหัส Base64" เป็นคำแนะนำอย่างเป็นทางการที่ได้รับการเขียนขึ้นอีกครั้ง (มีอยู่แล้วใน Javadoc) ในข้อบกพร่องเมื่อ 01/2019 ล่าสุดใน Chrominium (มีอยู่ใน WebView M72 (72.0.3626.76)):

https://bugs.chromium.org/p/chromium/issues/detail?id=929083

คำชี้แจงอย่างเป็นทางการจากทีม Chromium:

"การแก้ไขที่แนะนำ:
ทีมของเราขอแนะนำให้คุณเข้ารหัสข้อมูลด้วย Base64 เราได้ให้ตัวอย่างวิธีการดำเนินการดังกล่าว:

การแก้ไขนี้เข้ากันได้แบบย้อนหลัง (ใช้ได้กับ WebView เวอร์ชันก่อนหน้า) และควรเป็นหลักฐานในอนาคตด้วย (คุณจะไม่ประสบปัญหาความเข้ากันได้ในอนาคตเกี่ยวกับการเข้ารหัสเนื้อหา) "

ตัวอย่างโค้ด:

webView.loadData(
    Base64.encodeToString(
        htmlContent.getBytes(StandardCharsets.UTF_8),
        Base64.DEFAULT), // encode in Base64 encoded 
    "text/html; charset=utf-8", // utf-8 html content (personal recommendation)
    "base64"); // always use Base64 encoded data: NEVER PUT "utf-8" here (using base64 or not): This is wrong! 

1

คำตอบข้างต้นใช้ไม่ได้กับกรณีของฉัน คุณต้องระบุ utf-8 ในเมตาแท็ก

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    </head>
    <body>
        <!-- you content goes here -->
    </body>
</html>

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.