它是一个简单的 Web 应用程序,其中包含 Web 视图,并且有一个带有上传文件选项的注册页面。单击浏览按钮时尝试打开文件选择器但没有响应。我认为我的 gradle 文件中有一些问题。请帮我调试它。这是我的代码。
这是我的项目gradle
buildscript {
repositories {
google()
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.3'
classpath 'com.google.gms:google-services:3.2.1'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
这是我的应用程序 gradle
android {
compileSdkVersion 27
defaultConfig {
applicationId "com.androidapp.myApp"
minSdkVersion 15
targetSdkVersion 27
versionCode 2
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
useLibrary 'org.apache.http.legacy'
multiDexEnabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:support-v4:27.1.1'
implementation 'com.google.firebase:firebase-invites:16.0.1'
implementation 'com.google.firebase:firebase-messaging:17.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.squareup.okhttp3:okhttp:3.8.0'
implementation 'com.android.support:multidex:1.0.3'
}
apply plugin: 'com.google.gms.google-services'
不是gradle文件错误。您只需要提供如下所示的自定义 WebChromeClient。
class MyWebChromeClient extends WebChromeClient {
// For 3.0+ Devices (Start)
// onActivityResult attached before constructor
protected void openFileChooser(ValueCallback uploadMsg, String acceptType) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
}
// For Lollipop 5.0+ Devices
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public boolean onShowFileChooser(WebView mWebView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
if (uploadMessage != null) {
uploadMessage.onReceiveValue(null);
uploadMessage = null;
}
uploadMessage = filePathCallback;
Intent intent = fileChooserParams.createIntent();
try {
startActivityForResult(intent, REQUEST_SELECT_FILE);
} catch (ActivityNotFoundException e) {
uploadMessage = null;
Toast.makeText(WebLink.this, "Cannot Open File Chooser", Toast.LENGTH_LONG).show();
return false;
}
return true;
}
//For Android 4.1 only
protected void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
mUploadMessage = uploadMsg;
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
startActivityForResult(Intent.createChooser(intent, "File Chooser"), FILECHOOSER_RESULTCODE);
}
protected void openFileChooser(ValueCallback<Uri> uploadMsg) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
}
}
它在你的网络视图中,如下所示
webview.setWebChromeClient(new MyWebChromeClient());
一些其他有用的东西/变量要全局声明。
public ValueCallback<Uri[]> uploadMessage;
private ValueCallback<Uri> mUploadMessage;
public static final int REQUEST_SELECT_FILE = 100;
private final static int FILECHOOSER_RESULTCODE = 1;
确保您拥有所有读/写权限
更新
使用以下行提供对存储中的文件的访问。
webview.getSettings().setDomStorageEnabled(true);
webview.getSettings().setAllowContentAccess(true);
webview.getSettings().setAllowFileAccess(true);
// EDIT, add this line also
webview.getSettings().setJavaScriptEnabled(true);
更新2
在onActivityResult方法中获取结果。您可以使用如下给出的结果。
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (requestCode == REQUEST_SELECT_FILE) {
if (uploadMessage == null)
return;
uploadMessage.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, intent));
uploadMessage = null;
}
} else if (requestCode == FILECHOOSER_RESULTCODE) {
if (null == mUploadMessage)
return;
// Use MainActivity.RESULT_OK if you're implementing WebView inside Fragment
// Use RESULT_OK only if you're implementing WebView inside an Activity
Uri result = intent == null || resultCode != WebLink.RESULT_OK ? null : intent.getData();
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
} else
Toast.makeText(WebLink.this, "Failed to Upload Image", Toast.LENGTH_LONG).show();
}
此 Kotlin 代码适用于所有版本:
webView.settings.javaScriptEnabled = true
webView.settings.loadWithOverviewMode = true
webView.settings.useWideViewPort = true
webView.settings.domStorageEnabled = true
webView.settings.allowFileAccess=true
webView.settings.allowContentAccess=true
webView.settings.allowUniversalAccessFromFileURLs=true
webView.settings.allowFileAccessFromFileURLs=true
webView.settings.javaScriptCanOpenWindowsAutomatically=true
webView.loadUrl(Constants.URL)
webView.webChromeClient = object : WebChromeClient() {
override fun onShowFileChooser(
webView: WebView,
filePathCallback: ValueCallback<Array<Uri>>,
fileChooserParams: FileChooserParams
): Boolean {
if (mUMA != null) {
mUMA!!.onReceiveValue(null)
}
mUMA = filePathCallback
var takePictureIntent: Intent? = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
if (takePictureIntent!!.resolveActivity([email protected]()) != null) {
var photoFile: File? = null
try {
photoFile = createImageFile()
takePictureIntent.putExtra("PhotoPath", mCM)
} catch (ex: IOException) {
Log.e("Webview", "Image file creation failed", ex)
}
if (photoFile != null) {
mCM = "file:" + photoFile.getAbsolutePath()
takePictureIntent.putExtra(
MediaStore.EXTRA_OUTPUT,
Uri.fromFile(photoFile)
)
} else {
takePictureIntent = null
}
}
val contentSelectionIntent = Intent(Intent.ACTION_GET_CONTENT)
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE)
contentSelectionIntent.type = "*/*"
val intentArray: Array<Intent>
intentArray = takePictureIntent?.let { arrayOf(it) } ?: arrayOf<Intent>()
val chooserIntent = Intent(Intent.ACTION_CHOOSER)
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent)
chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser")
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray)
startActivityForResult(chooserIntent, FCR)
return true
}
}
// Create an image file
@Throws(IOException::class)
private fun createImageFile(): File? {
@SuppressLint("SimpleDateFormat") val timeStamp: String =
SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
val imageFileName = "img_" + timeStamp + "_"
val storageDir: File =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
return File.createTempFile(imageFileName, ".jpg", storageDir)
}
fun openFileChooser(uploadMsg: ValueCallback<Uri?>?) {
this.openFileChooser(uploadMsg, "*/*")
}
fun openFileChooser(
uploadMsg: ValueCallback<Uri?>?,
acceptType: String?
) {
this.openFileChooser(uploadMsg, acceptType, null)
}
fun openFileChooser(
uploadMsg: ValueCallback<Uri?>?,
acceptType: String?,
capture: String?
) {
val i = Intent(Intent.ACTION_GET_CONTENT)
i.addCategory(Intent.CATEGORY_OPENABLE)
i.type = "*/*"
[email protected](
Intent.createChooser(i, "File Browser"),
FILECHOOSER_RESULTCODE
)
}
override fun onActivityResult(
requestCode: Int,
resultCode: Int,
intent: Intent?
) {
super.onActivityResult(requestCode, resultCode, intent)
if (Build.VERSION.SDK_INT >= 21) {
var results: Array<Uri>? = null
//Check if response is positive
if (resultCode == Activity.RESULT_OK) {
if (requestCode == FCR) {
if (null == mUMA) {
return
}
if (intent == null) { //Capture Photo if no image available
if (mCM != null) {
results = arrayOf(Uri.parse(mCM))
}
} else {
val dataString = intent.dataString
if (dataString != null) {
results = arrayOf(Uri.parse(dataString))
}
}
}
}
mUMA!!.onReceiveValue(results)
mUMA = null
} else {
if (requestCode == FCR) {
if (null == mUM) return
val result =
if (intent == null || resultCode != Activity.RESULT_OK) null else intent.data
mUM!!.onReceiveValue(result)
mUM = null
}
}
}
/*needed fileds
private var mCM: String? = null
private var mUM: ValueCallback<Uri>? = null
private var mUMA: ValueCallback<Array<Uri>>? = null
private const val FCR = 1*/
Kotlin 在 2022-23 年变得如此简单。
class MainActivity : AppCompatActivity() {
private var fileChooserResultLauncher = createFileChooserResultLauncher()
private var fileChooserValueCallback: ValueCallback<Array<Uri>>? = null
webView.webChromeClient = object : WebChromeClient() {
override fun onShowFileChooser(webView: WebView?, filePathCallback: ValueCallback<Array<Uri>>?, fileChooserParams: FileChooserParams?): Boolean {
try {
fileChooserValueCallback = filePathCallback;
fileChooserResultLauncher.launch(fileChooserParams?.createIntent())
} catch (e: ActivityNotFoundException) {
// You may handle "No activity found to handle intent" error
}
return true
}
}
private fun createFileChooserResultLauncher(): ActivityResultLauncher<Intent> {
return registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == Activity.RESULT_OK) {
fileChooserValueCallback?.onReceiveValue(arrayOf(Uri.parse(it?.data?.dataString)));
} else {
fileChooserValueCallback?.onReceiveValue(null)
}
}
}
}
OzgurG 的上述解决方案有效。最后一个可行的解决方案。我有两个问题: - 每次应用程序只能访问所选图像时,都会显示一条消息。这可以隐藏/只询问一次吗?
-我也可以用这个方法启用相机上传吗?
谢谢!