当前位置: 首页 > 知识库问答 >
问题:

Android StudioSDK30(2021)webview如何使文件输入提示用户图库,照片或视频和实际上传

葛景龙
2023-03-14

Android Studio/SDK 30我需要上传到webview的输入文件中。

6年、7年到8年前,有大量答案不再有效:(

我有一个可以使用的工作网络视图。getUserMedia(webrtc),可以使用GPS,但无法在常规

此代码确实询问(当启动应用程序)相机,存储,gps的权限...

我想触发一个提示,要求用户拍照、拍摄视频或从gallery中选择,然后实际上传。

这是我的舱单

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.apptheway.wexview">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_GPS" />
    <uses-permission android:name="android.permission.ACCESS_ASSISTED_GPS" />
    <uses-permission android:name="android.permission.ACCESS_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
    <uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" android:maxSdkVersion="28" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.CAMERA2" />
    <uses-permission android:name="android.webkit.PermissionRequest" />
    <uses-permission android:name="com.android.vending.BILLING" />
    <uses-permission android:name="com.android.vending.CHECK_LICENSE" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera2" />
    <uses-feature android:name="android.hardware.location.gps" />
    <uses-feature android:name="android.hardware.location.network" />

    <application
        android:allowBackup="true"
        android:fullBackupContent="true"
        android:hardwareAccelerated="true"
        android:requestLegacyExternalStorage="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.AppCompat.NoActionBar">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

这里是主要活动

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Window;
import android.webkit.GeolocationPermissions;
import android.webkit.PermissionRequest;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Random;

@SuppressLint("SetJavaScriptEnabled")

public class MainActivity extends AppCompatActivity {

    private WebView mWebView;

    private ValueCallback<Uri> mUploadMessage;
    private final static int FILECHOOSER_RESULTCODE = 1;

    @Override
    protected void onStart() {
        super.onStart();

        String[] permissions = {
                Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.CAMERA,
                Manifest.permission.RECORD_AUDIO,
                Manifest.permission.MODIFY_AUDIO_SETTINGS,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
        };

        requestPermissions(permissions, 0);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        for (int i = 0; i < permissions.length; i++) {
            String permission = permissions[i];
            boolean isGranted = grantResults[i] >= 0;
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        getWindow().requestFeature(Window.FEATURE_NO_TITLE);

        mWebView = new WebView(this);
        WebSettings webSettings = mWebView.getSettings();
        webSettings.setLoadWithOverviewMode(true);
        webSettings.setUseWideViewPort(true);
        webSettings.setDomStorageEnabled(true);
        webSettings.setGeolocationEnabled(true);
        webSettings.setBuiltInZoomControls(true);
        webSettings.setDisplayZoomControls(false);
        webSettings.setSupportZoom(true);
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
        webSettings.setJavaScriptEnabled(true);
        webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
        webSettings.setAllowFileAccess(true);
        webSettings.setAllowContentAccess(true);
        webSettings.setDatabaseEnabled(true);
        webSettings.setMediaPlaybackRequiresUserGesture(false);
        webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);

        mWebView.setWebViewClient(new WebViewClient() {

            @Override
            public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {

                String url = request.getUrl().toString();

                int opensInWexView = 1;

                // DOMAINS
//                if ( !url.contains("stubfee.com") && !url.contains("stubfee.com") && !url.contains("stubfeedevent.com") ) {
//                    opensInWexView = 0;
//                }

                // IF FILE
                if (    url.contains(".pdf") || url.contains(".mov") || url.contains(".mp") ||
                        url.contains(".hv") || url.contains(".aif") || url.contains(".wav") ||
                        url.contains(".xls") || url.contains(".doc") || url.contains(".txt")
                ) {
                    opensInWexView = 0;
                }

                // URL SCHEME
                if (    url.startsWith("tel:") || url.startsWith("sms:") ||
                        url.startsWith("mms:") || url.startsWith("mailto:") ||
                        url.startsWith("fax:")
                ) {
                    opensInWexView = 0;
                }

                switch (opensInWexView) {
                    case 0:
                        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                        startActivity(intent);
                        break;
                    default:
                        view.loadUrl(url);
                        break;
                }

                return true;

            }
        });

        mWebView.setWebChromeClient(new WebChromeClient() {

            // CAMERA
            public void onPermissionRequest(final PermissionRequest request) {
                request.grant(request.getResources());
            }

            // GPS
            public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
                callback.invoke(origin, true, false);
            }

            // FILE INPUT

        });

        mWebView.loadUrl("https://www.stubfee.com/account/" + (new Random().nextInt((1000000 - 1) + 1) + 1) + "/");

        this.setContentView(mWebView);

    }

    @Override
    public boolean onKeyDown(final int keyCode, final KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
            mWebView.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

}

在许多答案中,他们谈到了在内部添加代码

mWebView.setWebChromeClient(new WebChromeClient() {}

但我尝试从网络的任何答案;它确实工作:(

在其中一个答案中,我打开了图库,但当选择一个文件时,什么也没有发生:(

有没有更近期的方法?

我错过了什么?

我试过了,但没有成功

在WebView中从相机或画廊上传图像

Android Webview从画廊或相机上传图像

使用Android FileProvider将照片和视频保存到图库

在WebView Android Studio中上传文件

如何在Android Studio中使用WebView上传文件?

如何使上传按钮在Android应用程序的工作?

谢谢


共有1个答案

邓鸿信
2023-03-14

我也遇到了同样的问题,并且在WebChromeClient上也遇到了问题,我最近找到了答案。onShowFileChooser是关键事件。(我在尝试将mWebView作为参数传递给一个新的类构造函数时遇到了麻烦,但是当我将定义保存在MainActive中时,它确实起作用了。)

此外,这种技术还避免了现在不推荐使用的startActivityForResultonActivityResult函数。

静态编程语言

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    supportActionBar!!.hide()
    val progressBarView = findViewById<ProgressBar>(R.id.webviewProgress)
    mWebview.settings.allowContentAccess = true
    mWebview.settings.allowFileAccess = true
    mWebview.settings.domStorageEnabled = true
    mWebview.settings.javaScriptEnabled = true
    mWebview.webViewClient = AppWebViewClient(progressBarView)
    mWebview.webChromeClient = object:WebChromeClient() {
        override fun onShowFileChooser(mWebView:WebView,
                                       filePathCallback:ValueCallback<Array<Uri>>,
                                       fileChooserParams:FileChooserParams):Boolean {
            if (mUploadMessage != null) {
                mUploadMessage!!.onReceiveValue(null)
                mUploadMessage = null
            }
            mUploadMessage = filePathCallback
            val contentSelectionIntent = Intent(Intent.ACTION_GET_CONTENT)
            contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE)
            contentSelectionIntent.type = "*/*"
            val intent = Intent(Intent.ACTION_CHOOSER)
            intent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent)
            intent.putExtra(Intent.EXTRA_TITLE, "File Chooser")
            try {
                getFileResultLauncher.launch(intent)
            } catch (e: ActivityNotFoundException) {
                mUploadMessage = null
                Toast.makeText(getApplicationContext(), "Cannot Open File Chooser", Toast.LENGTH_LONG).show()
                return false
            }
            return true
        }
    }
    mWebview.loadUrl(getString(R.string.app_url))

}

val getFileResultLauncher = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()
) {
    ar: ActivityResult ->
    val intent: Intent? = ar.data
    val result = if (intent == null || ar.resultCode != RESULT_OK) null else arrayOf(Uri.parse(intent.dataString))
    mUploadMessage!!.onReceiveValue(result);
    mUploadMessage = null;
}

override fun onBackPressed() {
    _webview.goBack()
}
 类似资料:
  • 我的应用程序(使用SDK小于24)可以使用相机拍照和视频。这些照片和视频可以在应用程序外的图库中查看。SDK 24及以上版本要求FileProvider创建uri,以便将照片或视频保存到多媒体资料中。 在SDK 24之前,我会使用uri和拍照意图: 使用SDK24及更高版本会出现异常: 我想使用FileProvider实现同样的目标(没有例外)。下面的实现可以拍照,但照片不会出现在图库中。我想知道

  • 我已经处理了文件选择器,它完美地上传了文件, <罢工> 问题出在相机上。一旦我试图上传相机照片,它崩溃了。据我所知,这是因为URI。 a)文件选择器:内容://media/external/images/1234 b)摄像:文件:///mnt/sdcard/pic.jpg <罢工> 它现在崩溃了,因为在尝试上传“content://media/external/images/1234”时出现了nu

  • 喂, 我使用一个webview,上面有一个按钮,可以浏览应用程序的照片库。 但是,当在webview中单击该按钮时,什么也不会发生。 url的格式为: 我已添加以下权限: 我有一个片段,它将在启用javascript的onCreateView方法(仅限代码段)中加载webview。

  • 本文向大家介绍iOS中读取照片库及保存图片或视频到照片库的要点解析,包括了iOS中读取照片库及保存图片或视频到照片库的要点解析的使用技巧和注意事项,需要的朋友参考一下 读取照片库PhotoLibrary iOS中如果我们只有一次读取一张图片或者一个视频(或拍一张照片/视频)的需求,那么我们用 UIImagePickerController 就可以搞定。但是很多时候我们需要一次性从PhotoLibr

  • 本文向大家介绍vue vantUI实现文件(图片、文档、视频、音频)上传(多文件),包括了vue vantUI实现文件(图片、文档、视频、音频)上传(多文件)的使用技巧和注意事项,需要的朋友参考一下 说在前面 网上有很多种文件上传的方法,根据公司最近的业务需求,要求实现多种文件的上传,在实现过程中,查阅了很多资料,最后,终于把功能实现了,开心! 上述html代码是在同一页面根据前一页面传回的col

  • 问题内容: 我遇到一种情况(在硒测试期间),在这种情况下,用户将收到安全代码。然后,用户必须先输入安全密码,然后才能继续操作。 我不太确定如何获得用户输入的值。我浏览了硒文档,并提出了这个建议。不幸的是,它并不是很有效。 有人可以指出我正确的方向吗? 问题答案: 似乎您必须先接受并关闭提示,然后才能存储和使用该值