I am making a webpage on-the-fly with Android's WebView, using Android Studio and a phone with OS version 11 connected by USB in developer mode.
Despite many questions about this, I can't load a file from external storage. This minimal example shows that I can do the job with an image in the assets
folder.
package com.example.hellowebview
import android.os.Bundle
import android.webkit.WebView
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val myWebView = WebView(this)
val myImage = "file:///android_asset/MonaLisa.jpg"
val myHtml = "<HTML><BODY><h3>Hello, WebView!</h3><img src='$myImage'></BODY></HTML>"
myWebView.loadDataWithBaseURL(null, myHtml, "text/html", "utf-8", null);
setContentView(myWebView)
}
}
But it won't load an image from the SD card. Here is my attempt, with variations.
package com.example.hellowebview
import android.Manifest
import android.os.Bundle
import android.os.Environment
import android.webkit.WebView
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val myWebView = WebView(this)
val PERMISSION_EXTERNAL_STORAGE = 1
requestPermissions(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), PERMISSION_EXTERNAL_STORAGE)
myWebView.getSettings().setAllowFileAccess(true);
val sdCard = Environment.getExternalStorageDirectory().absolutePath.toString()
val myImage = "file://$sdCard/Download/MonaLisa.jpg"
//val myImage = "file:///$sdCard/Download/MonaLisa.jpg"
//val myImage = "$sdCard/Download/MonaLisa.jpg"
//val myImage = "file:///Download/MonaLisa.jpg"
//val myImage = "file:///sdcard/Download/MonaLisa.jpg"
//val myImage = "file://sdcard/Download/MonaLisa.jpg"
val myHtml = "<HTML><BODY><h3>Hello, WebView!</h3><img src='$myImage'></BODY></HTML>"
//myWebView.loadDataWithBaseURL(sdCard, myHtml, "text/html", "utf-8", null)
myWebView.loadDataWithBaseURL(null, myHtml, "text/html", "utf-8", null)
setContentView(myWebView)
}
}
I also added these two lines to AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
and permission was requested (and given). The value of sdCard
is /storage/emulated/0
and the image file does exist:
What have I overlooked, or done wrong?
I can make an arbitrary folder on the SD card by hand, copy files from my PC by hand by USB, and view those files with other Android apps. So why can't I load those files with my app?
Bounty
I am aware that Google changed its policy with Android 11 to improve security. Yet it is possible to read images from the SD card as this example from GeeksforGeeks demonstrates:
How to Build a Photo Viewing Application in Android?
It is java not kotlin but no matter: it displays images in accessible folders, one of which I created at the phone and copied images from the PC. It works (although for some reason won't run twice but has to be uninstalled). It doesn't use a WebView
and I haven't been able to imitate it.
It does not have MANAGE_EXTERNAL_STORAGE
in the manifest, only READ_EXTERNAL_STORAGE
.
I have not posted the code requested by a comment, because I do not want the app to copy images to a folder from its assets. I want to be able to copy images from a PC directly, without placing them in assets and rebuilding the app.
So I would welcome answers to my question:
How do I use images from accessible SD card folders in an HTML <img>
tag in a WebView
using Android version 11?