ไฟล์อัพโหลดใน WebView


172

ฉันพยายามอัปโหลดไฟล์จาก WebView มาหลายวันแล้วและไม่มีความคืบหน้า ฉัน googled และใช้งานโซลูชั่นที่แนะนำทั้งหมด แต่ไม่มีงานเช่น: โซลูชั่นที่แนะนำที่นี่และอื่น ๆ

ปัญหา: ฉันมีหน้า HTML ที่มีรหัสต่อไปนี้เพื่ออัปโหลดไฟล์ มันทำงานได้ดีในเบราว์เซอร์เดสก์ท็อปเช่น Firefox และเบราว์เซอร์ emulator / AVD ในตัวเช่นเมื่อฉันคลิกปุ่ม "เรียกดู ... " ที่แสดงโดยองค์ประกอบเบราว์เซอร์จะเปิดกล่องโต้ตอบที่ฉันสามารถเลือกไฟล์ที่จะอัปโหลด

อย่างไรก็ตามใน android 3.0 emulator / AVD เมื่อฉันคลิกที่ "เลือกไฟล์" ไม่มีอะไรเกิดขึ้นไม่มีการเปิดไฟล์โต้ตอบ !!!

<form method="POST" enctype="multipart/form-data">
File to upload: <input type="file" name="uploadfile">&nbsp;&nbsp;
<input type="submit" value="Press to Upload..."> to upload the file!
</form>

ใครช่วยกรุณาแนะนำวิธีแก้ปัญหาที่เป็นไปได้อย่างเร็วที่สุด


คุณสามารถใช้Webviewคลาสย่อยนี้ซึ่งจัดการการอัปโหลดไฟล์ ฯลฯ โดยอัตโนมัติ: github.com/delight-im/Android-AdvancedWebView
caw

@MarcoW ฉันลองใช้ AdvancedWebView แล้ว แต่ยังไม่สามารถอัปโหลดไฟล์ได้
jiashie

@jiashie การอัปโหลดไฟล์ทำงานบน Android ทุกรุ่นยกเว้น Android 4.4 ซึ่งไม่มีโอกาสที่จะทำให้มันทำงานได้ บางทีคุณอยู่ในรุ่นนั้น มิฉะนั้นคุณสามารถตรวจสอบAdvancedWebView.isFileUploadAvailable()ว่ามีการสนับสนุนการอัปโหลดหรือไม่ และคุณสามารถแบ่งปันรหัสของคุณและขอความช่วยเหลือในปัญหา: github.com/delight-im/Android-AdvancedWebView/issues
caw

@hiram ฉันสามารถอัปโหลดไฟล์ผ่าน iframe ใน webview ในแอพ android ของฉันได้อย่างไรฉันต้องทำอย่างไร
Gaurav Parashar

คำตอบ:


162

นี่เป็นโซลูชั่นที่สมบูรณ์สำหรับ Android ทุกรุ่นฉันมีช่วงเวลาที่ยากลำบากเช่นกัน

public class MyWb extends Activity {
/** Called when the activity is first created. */

WebView web;
ProgressBar progressBar;

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

 @Override  
 protected void onActivityResult(int requestCode, int resultCode,  
                                    Intent intent) {  
  if(requestCode==FILECHOOSER_RESULTCODE)  
  {  
   if (null == mUploadMessage) return;  
            Uri result = intent == null || resultCode != RESULT_OK ? null  
                    : intent.getData();  
            mUploadMessage.onReceiveValue(result);  
            mUploadMessage = null;  
  }
  }  

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    web = (WebView) findViewById(R.id.webview01);
    progressBar = (ProgressBar) findViewById(R.id.progressBar1);

    web = new WebView(this);  
    web.getSettings().setJavaScriptEnabled(true);
    web.loadUrl("http://www.script-tutorials.com/demos/199/index.html");
    web.setWebViewClient(new myWebClient());
    web.setWebChromeClient(new WebChromeClient()  
    {  
           //The undocumented magic method override  
           //Eclipse will swear at you if you try to put @Override here  
        // For Android 3.0+
        public void openFileChooser(ValueCallback<Uri> uploadMsg) {  

            mUploadMessage = uploadMsg;  
            Intent i = new Intent(Intent.ACTION_GET_CONTENT);  
            i.addCategory(Intent.CATEGORY_OPENABLE);  
            i.setType("image/*");  
            MyWb.this.startActivityForResult(Intent.createChooser(i,"File Chooser"), FILECHOOSER_RESULTCODE);  

           }

        // For Android 3.0+
           public void openFileChooser( ValueCallback uploadMsg, String acceptType ) {
           mUploadMessage = uploadMsg;
           Intent i = new Intent(Intent.ACTION_GET_CONTENT);
           i.addCategory(Intent.CATEGORY_OPENABLE);
           i.setType("*/*");
           MyWb.this.startActivityForResult(
           Intent.createChooser(i, "File Browser"),
           FILECHOOSER_RESULTCODE);
           }

        //For Android 4.1
           public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture){
               mUploadMessage = uploadMsg;  
               Intent i = new Intent(Intent.ACTION_GET_CONTENT);  
               i.addCategory(Intent.CATEGORY_OPENABLE);  
               i.setType("image/*");  
               MyWb.this.startActivityForResult( Intent.createChooser( i, "File Chooser" ), MyWb.FILECHOOSER_RESULTCODE );

           }

    });  


    setContentView(web);  


}

public class myWebClient extends WebViewClient
{
    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        // TODO Auto-generated method stub
        super.onPageStarted(view, url, favicon);
    }

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        // TODO Auto-generated method stub

        view.loadUrl(url);
        return true;

    }

    @Override
    public void onPageFinished(WebView view, String url) {
        // TODO Auto-generated method stub
        super.onPageFinished(view, url);

        progressBar.setVisibility(View.GONE);
    }
}

//flipscreen not loading again
@Override
public void onConfigurationChanged(Configuration newConfig){        
    super.onConfigurationChanged(newConfig);
}

// To handle "Back" key press event for WebView to go back to previous screen.
/*@Override
public boolean onKeyDown(int keyCode, KeyEvent event) 
{
    if ((keyCode == KeyEvent.KEYCODE_BACK) && web.canGoBack()) {
        web.goBack();
        return true;
    }
    return super.onKeyDown(keyCode, event);
}*/
}

นอกจากนี้ฉันต้องการเพิ่มว่า "หน้าการอัปโหลด" เหมือนในตัวอย่างนี้จะไม่ทำงานใน <4 รุ่นเนื่องจากมันมีคุณสมบัติการแสดงตัวอย่างรูปภาพหากคุณต้องการทำให้มันใช้งานได้ง่ายอัปโหลด php โดยไม่ต้องดูตัวอย่าง

อัปเดต :

กรุณาหาวิธีแก้ปัญหาสำหรับอุปกรณ์อมยิ้มที่นี่และขอขอบคุณสำหรับgauntface

อัปเดต 2 :

วิธีแก้ปัญหาที่สมบูรณ์สำหรับอุปกรณ์ Android ทั้งหมดจนถึงoreo ที่นี่และนี่เป็นเวอร์ชั่นขั้นสูงกว่านี้คุณควรลองเข้าไปดูบางทีมันอาจช่วยได้


ขอบคุณโคลนมากที่ช่วยประหยัดเวลาของฉัน!
Ramesh Akula

20
@hifarrer คุณเป็นผู้ช่วยชีวิต มันใช้งานได้ดี นอกจากนี้สำหรับเรา noobs รหัสที่สมบูรณ์ช่วยให้เข้าใจตำแหน่งและวิธีการทำงานมากกว่าแค่การวางฟังก์ชั่นมากมายแล้วเราก็ไม่รู้ว่าจะวางและใช้งานที่ไหน ขอบคุณสำหรับการตอบกลับอย่างละเอียด
แจ็คปานามา

วิธีจัดการกับวิธีนี้หลังจากทำให้งงงวย? ฉันใช้วิธีการเดียวกันโดยไม่ทำให้งงงวยมันทำงานได้ดี แต่เมื่อแอพของฉันถูกปรับใช้ด้วยการทำให้งงงวยวิธีนี้จะไม่ถูกเรียก ฉันเก็บวิธีนี้ไว้ในพรอมต์เพื่อให้ทุกคนเห็นปัญหานี้หรือไม่
Harshawardhan

1
มันใช้งานได้ แต่ทำไมค่าถึงไม่อัพเดทตามที่ควรจะเป็น? นั่นคือการทดสอบของฉันเกี่ยวกับ Eclipse Android API17 emulator
เจฟฟรีย์นีโอ

1
progressBarดูเหมือนไม่ได้ใช้มี ฉันเห็นได้เพียงซ่อน แต่ไม่ใช่ที่เปิดใช้งาน ฉันคิดว่าคุณจะต้องเพิ่ม ตัวแปรที่onProgressChanged(...)กำหนดเองWebChromeClientสำหรับสิ่งนั้น (และสิ่งที่ชอบgetWindow().setFeatureInt( Window.FEATURE_PROGRESS, Window.PROGRESS_VISIBILITY_ON);เข้าไปonCreate)
Sz.

106

วิธีการทำงานจาก HONEYCOMB (API 11) ถึง Oreo (API 27)
[ยังไม่ผ่านการทดสอบบน 9.0

static WebView mWebView;
private ValueCallback<Uri> mUploadMessage;
public ValueCallback<Uri[]> uploadMessage;
public static final int REQUEST_SELECT_FILE = 100;
private final static int FILECHOOSER_RESULTCODE = 1;

ดัดแปลง 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 != MainActivity.RESULT_OK ? null : intent.getData();
        mUploadMessage.onReceiveValue(result);
        mUploadMessage = null;
    }
    else
        Toast.makeText(getActivity().getApplicationContext(), "Failed to Upload Image", Toast.LENGTH_LONG).show();
}

ตอนนี้ในonCreate()หรือonCreateView()วางรหัสต่อไปนี้

    WebSettings mWebSettings = mWebView.getSettings();
    mWebSettings.setJavaScriptEnabled(true);
    mWebSettings.setSupportZoom(false);
    mWebSettings.setAllowFileAccess(true);
    mWebSettings.setAllowFileAccess(true);
    mWebSettings.setAllowContentAccess(true);

mWebView.setWebChromeClient(new 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 Browser"), FILECHOOSER_RESULTCODE);
    }


    // For Lollipop 5.0+ Devices
    public boolean onShowFileChooser(WebView mWebView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.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(getActivity().getApplicationContext(), "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 Browser"), 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);
    }
});

แก้ไขปัญหาของฉัน ขอบคุณ.
Htin Aung

1
ขอบคุณสำหรับรหัสเต็มของคุณ มันใช้งานได้ดียกเว้น kitkat Os คุณช่วยให้ฉันทราบวิธีการสนับสนุนใน kitkat ใด ๆ ขอบคุณ
AndyBoy

คำตอบที่สมบูรณ์แบบ !! ขอบคุณมาก @zackygaurav
Swr7der

ทำงานอย่างสมบูรณ์แบบ
Hitesh Sahu

1
@NightFury คุณต้องทำเช่นนี้หากคุณพยายามเข้าถึงลิงค์http ใช้httpsแทน
zackygaurav

45

นี่เป็นทางออกเดียวที่ฉันพบว่าใช้งานได้!

WebView webview;

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

@Override
protected void onActivityResult(int requestCode, int resultCode,
        Intent intent) {
    if (requestCode == FILECHOOSER_RESULTCODE) {
        if (null == mUploadMessage)
            return;
        Uri result = intent == null || resultCode != RESULT_OK ? null
                : intent.getData();
        mUploadMessage.onReceiveValue(result);
        mUploadMessage = null;

    }
}

// Next part 

class MyWebChromeClient extends WebChromeClient {
    // The undocumented magic method override
    // Eclipse will swear at you if you try to put @Override here
    public void openFileChooser(ValueCallback<Uri> uploadMsg) {

        mUploadMessage = uploadMsg;
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);
        i.setType("image/*");
        Cv5appActivity.this.startActivityForResult(
                Intent.createChooser(i, "Image Browser"),
                FILECHOOSER_RESULTCODE);
    }
}

3
คุณช่วยอธิบายได้อย่างชัดเจนว่าฉันควรวางรหัสนี้ไว้ที่ไหน และฉันควรใช้มันอย่างไร?
CAMOBAP

27
ตั้งแต่ 4.4 (KitKat) openFileChooser ไม่สามารถใช้งานได้อีกต่อไปดังนั้นวิธีการที่ใช้งานไม่ได้
Steve N

4
@nadeemgc ในกรณีของฉันฉันควบคุมเว็บเซิร์ฟเวอร์ด้วยดังนั้นฉันกำลังตรวจสอบ Android 4.4+ โดยใช้รูปแบบ URL อื่น (หรือที่รู้จักกันว่า "my-app: // some / other / arguments") สำหรับลิงค์อัปโหลดขัดขวาง URL เหล่านี้ ใน shouldOverrideUrlLoading () จากนั้นแสดงตัวเลือก & ทำการอัพโหลดในโค้ดเนทีฟสำหรับกรณีนั้น มันไม่ได้เป็นวิธีแก้ปัญหาที่มีน้ำหนักเบา
Steve N

2
ฉันสามารถอัพโหลดรูปภาพใน android 4.4.2 โดยใช้ webview ได้หรือไม่?
BABU K

@SteveN คุณสามารถให้ข้อมูลโค้ดได้หรือไม่ มันจะยอดเยี่ยม!
Gp2mv3

28

ใน 5.0 Lollipop, Google ได้เพิ่มวิธีการอย่างเป็นทางการWebChromeClient.onShowFileChooser พวกเขายังมีวิธีในการสร้างเจตนาเลือกไฟล์โดยอัตโนมัติเพื่อให้ใช้อินพุตยอมรับชนิด mime

public class MyWebChromeClient extends WebChromeClient {
        // reference to activity instance. May be unnecessary if your web chrome client is member class.
    private MyActivity activity;

    public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
        // make sure there is no existing message
        if (myActivity.uploadMessage != null) {
            myActivity.uploadMessage.onReceiveValue(null);
            myActivity.uploadMessage = null;
        }

        myActivity.uploadMessage = filePathCallback;

        Intent intent = fileChooserParams.createIntent();
        try {
            myActivity.startActivityForResult(intent, MyActivity.REQUEST_SELECT_FILE);
        } catch (ActivityNotFoundException e) {
            myActivity.uploadMessage = null;
            Toast.makeText(myActivity, "Cannot open file chooser", Toast.LENGTH_LONG).show();
            return false;
        }

        return true;
    }
}


public class MyActivity extends ... {
    public static final int REQUEST_SELECT_FILE = 100;
    public ValueCallback<Uri[]> uploadMessage;

    protected void onActivityResult(int requestCode, int resultCode, Intent data){
        if (requestCode == REQUEST_SELECT_FILE) {
                if (uploadMessage == null) return;
                uploadMessage.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, data));
                uploadMessage = null;
            }
        }
    }
}

สำหรับรุ่น Android ก่อน KitKat วิธีการส่วนตัวที่กล่าวถึงในคำตอบอื่น ๆ นั้นใช้งานได้ ฉันไม่พบวิธีแก้ปัญหาที่ดีสำหรับ KitKat (4.4)


ในสถานการณ์ของฉันใช้uploadMessage.onReceiveValue()งานได้และมีการปิด)
Ninja

สิ่งนี้ไม่ได้ผลสำหรับฉัน ฉันพยายามสร้างคลาสใหม่ที่เรียกว่า 'MyWebChromeClient' ด้วยรหัสของคุณ แต่พบว่า MyActivity เป็นคลาสที่ฉันไม่สามารถนำเข้าได้ ... ฉันสามารถสร้างคลาสของตัวเองที่ชื่อว่า 'MyActivity' แต่ฉันไม่รู้ว่าจะใส่อะไร เป็นมัน
rikkitikkitumbo

19

ฉันพบว่าฉันต้องการนิยามอินเทอร์เฟซ 3 ประการเพื่อจัดการ Android รุ่นต่างๆ

public void openFileChooser(ValueCallback < Uri > uploadMsg) {
  mUploadMessage = uploadMsg;
  Intent i = new Intent(Intent.ACTION_GET_CONTENT);
  i.addCategory(Intent.CATEGORY_OPENABLE);
  i.setType("image/*");
  FreeHealthTrack.this.startActivityForResult(Intent.createChooser(i, "Image Chooser"), FILECHOOSER_RESULTCODE);
}

public void openFileChooser(ValueCallback < Uri > uploadMsg, String acceptType) {
  openFileChooser(uploadMsg);
}

public void openFileChooser(ValueCallback < Uri > uploadMsg, String acceptType, String capture) {
  openFileChooser(uploadMsg);
}

3
ขอบคุณสุดท้ายต้องใช้ Jelly Bean ซึ่งเป็นอันที่ใช้ไม่ได้สำหรับฉัน
shalafi

3
วิธีจัดการกับวิธีนี้หลังจากทำให้งงงวย? ฉันใช้วิธีการเดียวกันโดยไม่ทำให้งงงวยมันทำงานได้ดี แต่เมื่อแอพของฉันถูกปรับใช้ด้วยการทำให้งงงวยวิธีนี้จะไม่ถูกเรียก ฉันเก็บวิธีนี้ไว้ในพรอมต์เพื่อให้ทุกคนเห็นปัญหานี้หรือไม่
Harshawardhan

2
มันจะเป็นการดีกว่าที่จะทำอีกด้านหนึ่งเช่นใส่รหัสในรหัสสุดท้ายที่มีลายเซ็นที่รวยที่สุดและใช้พารามิเตอร์เพื่อเลือกชนิดของการเปิดตัว จากนั้นให้อีกสองคนเรียกอันสุดท้ายที่มีค่าเริ่มต้นสำหรับพารามิเตอร์เหล่านั้น
matteo

16

วิธีนี้ใช้ได้กับ Honeycomb และ Ice Cream Sandwich ดูเหมือนว่า Google จะนำเสนอคุณลักษณะใหม่ที่ยอดเยี่ยม (ยอมรับคุณสมบัติ) และลืมที่จะใช้งานเกินพิกัดสำหรับความเข้ากันได้ย้อนหลัง

protected class CustomWebChromeClient extends WebChromeClient
{
    // For Android 3.0+
    public void openFileChooser( ValueCallback<Uri> uploadMsg, String acceptType ) 
    {  
        context.mUploadMessage = uploadMsg;  
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);  
        i.addCategory(Intent.CATEGORY_OPENABLE);  
        i.setType("image/*");  
        context.startActivityForResult( Intent.createChooser( i, "File Chooser" ), MainActivity.FILECHOOSER_RESULTCODE );  
    }

    // For Android < 3.0
    public void openFileChooser( ValueCallback<Uri> uploadMsg ) 
    {
        openFileChooser( uploadMsg, "" );
    }
}

คุณช่วยอธิบายได้อย่างชัดเจนว่าฉันควรจะวางคลาสนี้ที่ไหน? และฉันควรใช้มันอย่างไร? ขอบคุณ
CAMOBAP

วางคลาสนี้ที่ใดก็ได้ในกิจกรรมของคุณ & ใช้รหัสนี้ webview.setWebChromeClient (CustomWebChromeClient ใหม่ ());
Vishal Pawar


5
ตั้งแต่ 4.4 (KitKat) openFileChooser ไม่สามารถใช้งานได้อีกต่อไปดังนั้นวิธีการที่ใช้งานไม่ได้
Steve N

16

การแก้ปัญหาอย่างเต็มรูปแบบของ hifarrer มีประโยชน์มากสำหรับฉัน

แต่ฉันพบปัญหาอื่น ๆ อีกมากมาย - รองรับประเภท mime อื่น ๆ , รายการอุปกรณ์จับภาพ (กล้อง, วิดีโอ, เครื่องบันทึกเสียง), เปิดอุปกรณ์จับภาพทันที (เช่น: <input accept = "image / *; capture">) ...

ดังนั้นฉันจึงสร้างโซลูชันที่ทำงานเหมือนกับแอปเว็บเบราว์เซอร์เริ่มต้น

ฉันใช้ android-4.4.3_r1 / src / com / android / เบราว์เซอร์ / UploadHandler.java (ขอบคุณ Rupert Rawnsley)

package org.mospi.agatenativewebview;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.webkit.JsResult;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebSettings.PluginState;
import android.widget.Toast;

public class MainActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        WebView webView = (WebView) findViewById(R.id.webView1);

        initWebView(webView);
        webView.loadUrl("http://google.com"); // TODO input your url

    }

    private final static Object methodInvoke(Object obj, String method, Class<?>[] parameterTypes, Object[] args) {
        try {
            Method m = obj.getClass().getMethod(method, new Class[] { boolean.class });
            m.invoke(obj, args);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    private void initWebView(WebView webView) {

        WebSettings settings = webView.getSettings();

        settings.setJavaScriptEnabled(true);
        settings.setAllowFileAccess(true);
        settings.setDomStorageEnabled(true);
        settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
        settings.setLoadWithOverviewMode(true);
        settings.setUseWideViewPort(true);
        settings.setSupportZoom(true);
        // settings.setPluginsEnabled(true);
        methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true });
        // settings.setPluginState(PluginState.ON);
        methodInvoke(settings, "setPluginState", new Class[] { PluginState.class }, new Object[] { PluginState.ON });
        // settings.setPluginsEnabled(true);
        methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true });
        // settings.setAllowUniversalAccessFromFileURLs(true);
        methodInvoke(settings, "setAllowUniversalAccessFromFileURLs", new Class[] { boolean.class }, new Object[] { true });
        // settings.setAllowFileAccessFromFileURLs(true);
        methodInvoke(settings, "setAllowFileAccessFromFileURLs", new Class[] { boolean.class }, new Object[] { true });

        webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
        webView.clearHistory();
        webView.clearFormData();
        webView.clearCache(true);

        webView.setWebChromeClient(new MyWebChromeClient());
        // webView.setDownloadListener(downloadListener);
    }

    UploadHandler mUploadHandler;

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {

        if (requestCode == Controller.FILE_SELECTED) {
            // Chose a file from the file picker.
            if (mUploadHandler != null) {
                mUploadHandler.onResult(resultCode, intent);
            }
        }

        super.onActivityResult(requestCode, resultCode, intent);
    }

    class MyWebChromeClient extends WebChromeClient {
        public MyWebChromeClient() {

        }

        private String getTitleFromUrl(String url) {
            String title = url;
            try {
                URL urlObj = new URL(url);
                String host = urlObj.getHost();
                if (host != null && !host.isEmpty()) {
                    return urlObj.getProtocol() + "://" + host;
                }
                if (url.startsWith("file:")) {
                    String fileName = urlObj.getFile();
                    if (fileName != null && !fileName.isEmpty()) {
                        return fileName;
                    }
                }
            } catch (Exception e) {
                // ignore
            }

            return title;
        }

        @Override
        public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
            String newTitle = getTitleFromUrl(url);

            new AlertDialog.Builder(MainActivity.this).setTitle(newTitle).setMessage(message).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {
                    result.confirm();
                }
            }).setCancelable(false).create().show();
            return true;
            // return super.onJsAlert(view, url, message, result);
        }

        @Override
        public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {

            String newTitle = getTitleFromUrl(url);

            new AlertDialog.Builder(MainActivity.this).setTitle(newTitle).setMessage(message).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {
                    result.confirm();
                }
            }).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    result.cancel();
                }
            }).setCancelable(false).create().show();
            return true;

            // return super.onJsConfirm(view, url, message, result);
        }

        // Android 2.x
        public void openFileChooser(ValueCallback<Uri> uploadMsg) {
            openFileChooser(uploadMsg, "");
        }

        // Android 3.0
        public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
            openFileChooser(uploadMsg, "", "filesystem");
        }

        // Android 4.1
        public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
            mUploadHandler = new UploadHandler(new Controller());
            mUploadHandler.openFileChooser(uploadMsg, acceptType, capture);
        }

        // Android 4.4, 4.4.1, 4.4.2
        // openFileChooser function is not called on Android 4.4, 4.4.1, 4.4.2,
        // you may use your own java script interface or other hybrid framework.          

        // Android 5.0.1
        public boolean onShowFileChooser(
                WebView webView, ValueCallback<Uri[]> filePathCallback,
                FileChooserParams fileChooserParams) {

            String acceptTypes[] = fileChooserParams.getAcceptTypes();

            String acceptType = "";
            for (int i = 0; i < acceptTypes.length; ++ i) {
                if (acceptTypes[i] != null && acceptTypes[i].length() != 0)
                    acceptType += acceptTypes[i] + ";";
            }
            if (acceptType.length() == 0)
                acceptType = "*/*";

            final ValueCallback<Uri[]> finalFilePathCallback = filePathCallback;

            ValueCallback<Uri> vc = new ValueCallback<Uri>() {

                @Override
                public void onReceiveValue(Uri value) {

                    Uri[] result;
                    if (value != null)
                        result = new Uri[]{value};
                    else
                        result = null;

                    finalFilePathCallback.onReceiveValue(result);

                }
            };

            openFileChooser(vc, acceptType, "filesystem");


            return true;
       }
    };

    class Controller {
        final static int FILE_SELECTED = 4;

        Activity getActivity() {
            return MainActivity.this;
        }
    }

    // copied from android-4.4.3_r1/src/com/android/browser/UploadHandler.java
    //////////////////////////////////////////////////////////////////////

    /*
     * Copyright (C) 2010 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */

    // package com.android.browser;
    //
    // import android.app.Activity;
    // import android.content.ActivityNotFoundException;
    // import android.content.Intent;
    // import android.net.Uri;
    // import android.os.Environment;
    // import android.provider.MediaStore;
    // import android.webkit.ValueCallback;
    // import android.widget.Toast;
    //
    // import java.io.File;
    // import java.util.Vector;
    //
    // /**
    // * Handle the file upload callbacks from WebView here
    // */
    // public class UploadHandler {

    class UploadHandler {
        /*
         * The Object used to inform the WebView of the file to upload.
         */
        private ValueCallback<Uri> mUploadMessage;
        private String mCameraFilePath;
        private boolean mHandled;
        private boolean mCaughtActivityNotFoundException;
        private Controller mController;
        public UploadHandler(Controller controller) {
            mController = controller;
        }
        String getFilePath() {
            return mCameraFilePath;
        }
        boolean handled() {
            return mHandled;
        }
        void onResult(int resultCode, Intent intent) {
            if (resultCode == Activity.RESULT_CANCELED && mCaughtActivityNotFoundException) {
                // Couldn't resolve an activity, we are going to try again so skip
                // this result.
                mCaughtActivityNotFoundException = false;
                return;
            }
            Uri result = intent == null || resultCode != Activity.RESULT_OK ? null
                    : intent.getData();
            // As we ask the camera to save the result of the user taking
            // a picture, the camera application does not return anything other
            // than RESULT_OK. So we need to check whether the file we expected
            // was written to disk in the in the case that we
            // did not get an intent returned but did get a RESULT_OK. If it was,
            // we assume that this result has came back from the camera.
            if (result == null && intent == null && resultCode == Activity.RESULT_OK) {
                File cameraFile = new File(mCameraFilePath);
                if (cameraFile.exists()) {
                    result = Uri.fromFile(cameraFile);
                    // Broadcast to the media scanner that we have a new photo
                    // so it will be added into the gallery for the user.
                    mController.getActivity().sendBroadcast(
                            new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, result));
                }
            }
            mUploadMessage.onReceiveValue(result);
            mHandled = true;
            mCaughtActivityNotFoundException = false;
        }
        void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
            final String imageMimeType = "image/*";
            final String videoMimeType = "video/*";
            final String audioMimeType = "audio/*";
            final String mediaSourceKey = "capture";
            final String mediaSourceValueCamera = "camera";
            final String mediaSourceValueFileSystem = "filesystem";
            final String mediaSourceValueCamcorder = "camcorder";
            final String mediaSourceValueMicrophone = "microphone";
            // According to the spec, media source can be 'filesystem' or 'camera' or 'camcorder'
            // or 'microphone' and the default value should be 'filesystem'.
            String mediaSource = mediaSourceValueFileSystem;
            if (mUploadMessage != null) {
                // Already a file picker operation in progress.
                return;
            }
            mUploadMessage = uploadMsg;
            // Parse the accept type.
            String params[] = acceptType.split(";");
            String mimeType = params[0];
            if (capture.length() > 0) {
                mediaSource = capture;
            }
            if (capture.equals(mediaSourceValueFileSystem)) {
                // To maintain backwards compatibility with the previous implementation
                // of the media capture API, if the value of the 'capture' attribute is
                // "filesystem", we should examine the accept-type for a MIME type that
                // may specify a different capture value.
                for (String p : params) {
                    String[] keyValue = p.split("=");
                    if (keyValue.length == 2) {
                        // Process key=value parameters.
                        if (mediaSourceKey.equals(keyValue[0])) {
                            mediaSource = keyValue[1];
                        }
                    }
                }
            }
            //Ensure it is not still set from a previous upload.
            mCameraFilePath = null;
            if (mimeType.equals(imageMimeType)) {
                if (mediaSource.equals(mediaSourceValueCamera)) {
                    // Specified 'image/*' and requested the camera, so go ahead and launch the
                    // camera directly.
                    startActivity(createCameraIntent());
                    return;
                } else {
                    // Specified just 'image/*', capture=filesystem, or an invalid capture parameter.
                    // In all these cases we show a traditional picker filetered on accept type
                    // so launch an intent for both the Camera and image/* OPENABLE.
                    Intent chooser = createChooserIntent(createCameraIntent());
                    chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(imageMimeType));
                    startActivity(chooser);
                    return;
                }
            } else if (mimeType.equals(videoMimeType)) {
                if (mediaSource.equals(mediaSourceValueCamcorder)) {
                    // Specified 'video/*' and requested the camcorder, so go ahead and launch the
                    // camcorder directly.
                    startActivity(createCamcorderIntent());
                    return;
               } else {
                    // Specified just 'video/*', capture=filesystem or an invalid capture parameter.
                    // In all these cases we show an intent for the traditional file picker, filtered
                    // on accept type so launch an intent for both camcorder and video/* OPENABLE.
                    Intent chooser = createChooserIntent(createCamcorderIntent());
                    chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(videoMimeType));
                    startActivity(chooser);
                    return;
                }
            } else if (mimeType.equals(audioMimeType)) {
                if (mediaSource.equals(mediaSourceValueMicrophone)) {
                    // Specified 'audio/*' and requested microphone, so go ahead and launch the sound
                    // recorder.
                    startActivity(createSoundRecorderIntent());
                    return;
                } else {
                    // Specified just 'audio/*',  capture=filesystem of an invalid capture parameter.
                    // In all these cases so go ahead and launch an intent for both the sound
                    // recorder and audio/* OPENABLE.
                    Intent chooser = createChooserIntent(createSoundRecorderIntent());
                    chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(audioMimeType));
                    startActivity(chooser);
                    return;
                }
            }
            // No special handling based on the accept type was necessary, so trigger the default
            // file upload chooser.
            startActivity(createDefaultOpenableIntent());
        }
        private void startActivity(Intent intent) {
            try {
                mController.getActivity().startActivityForResult(intent, Controller.FILE_SELECTED);
            } catch (ActivityNotFoundException e) {
                // No installed app was able to handle the intent that
                // we sent, so fallback to the default file upload control.
                try {
                    mCaughtActivityNotFoundException = true;
                    mController.getActivity().startActivityForResult(createDefaultOpenableIntent(),
                            Controller.FILE_SELECTED);
                } catch (ActivityNotFoundException e2) {
                    // Nothing can return us a file, so file upload is effectively disabled.
                    Toast.makeText(mController.getActivity(), R.string.uploads_disabled,
                            Toast.LENGTH_LONG).show();
                }
            }
        }
        private Intent createDefaultOpenableIntent() {
            // Create and return a chooser with the default OPENABLE
            // actions including the camera, camcorder and sound
            // recorder where available.
            Intent i = new Intent(Intent.ACTION_GET_CONTENT);
            i.addCategory(Intent.CATEGORY_OPENABLE);
            i.setType("*/*");
            Intent chooser = createChooserIntent(createCameraIntent(), createCamcorderIntent(),
                    createSoundRecorderIntent());
            chooser.putExtra(Intent.EXTRA_INTENT, i);
            return chooser;
        }
        private Intent createChooserIntent(Intent... intents) {
            Intent chooser = new Intent(Intent.ACTION_CHOOSER);
            chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents);
            chooser.putExtra(Intent.EXTRA_TITLE,
                    mController.getActivity().getResources()
                            .getString(R.string.choose_upload));
            return chooser;
        }
        private Intent createOpenableIntent(String type) {
            Intent i = new Intent(Intent.ACTION_GET_CONTENT);
            i.addCategory(Intent.CATEGORY_OPENABLE);
            i.setType(type);
            return i;
        }
        private Intent createCameraIntent() {
            Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            File externalDataDir = Environment.getExternalStoragePublicDirectory(
                    Environment.DIRECTORY_DCIM);
            File cameraDataDir = new File(externalDataDir.getAbsolutePath() +
                    File.separator + "browser-photos");
            cameraDataDir.mkdirs();
            mCameraFilePath = cameraDataDir.getAbsolutePath() + File.separator +
                    System.currentTimeMillis() + ".jpg";
            cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mCameraFilePath)));
            return cameraIntent;
        }
        private Intent createCamcorderIntent() {
            return new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
        }
        private Intent createSoundRecorderIntent() {
            return new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
        }
    }
}

resoruce สตริงเพิ่มเติมของ res / values ​​/ string.xml:

<string name="uploads_disabled">File uploads are disabled.</string>
<string name="choose_upload">Choose file for upload</string>

หากคุณใช้ proguard คุณอาจต้องการตัวเลือกด้านล่างใน proguard-project.txt:

-keepclassmembers class * extends android.webkit.WebChromeClient {
   public void openFileChooser(...);
}

อัปเดต # 1 (2015.09.09)

เพิ่มรหัสสำหรับ Android 5.0.1 ความเข้ากันได้


ไม่สามารถทำให้มันทำงานได้ใน 4.4.2 คุณได้ทดสอบกับ android 4.4.2
Ana Llera

2
ฟังก์ชั่น @Anna openFileChooser ไม่ได้ถูกเรียกบน Android 4.4, 4.4.1, 4.4.2 ข้อผิดพลาดนี้ได้รับการแก้ไขใน Android 4.4.3 ref.) http://code.google.com/p/android/issues/detail?id=62220แต่น่าเศร้าที่หลายคนใช้ 4.4.2 ฉันคิดว่าคุณอาจใช้อินเตอร์เฟสสคริปต์ของจาวา (ดูคำตอบของ DanelK) หรือไฮบริดเฟรมเวิร์กอื่น ๆ (Cordova, phonegap, agate ... ) ในกรณีของฉันฉันไม่สามารถแก้ไขไฟล์ HTML บนเซิร์ฟเวอร์ได้ ดังนั้นฉันจึงใช้ปลั๊กอินสคริปต์ Agate WebView Java AgateWebViewFileUpload_AndroidEclipse
UnknownStack

@UnknownStack ฉันกำลังพยายามใช้งานการอัปโหลด Webview Fil แบบโมรา แทนที่จะเป็นหน้า htm ฉันต้องการตั้ง url เป็น webview, ฉันจะทำอย่างไร
Tushar Narang

@tusharnarang เปิดไฟล์ "assets / moml / ui / webView.xml" จากนั้นค้นหาแอตทริบิวต์ AGATEWEBVIEW.src และแทนที่ค่า "index.htm" เป็น URL ของคุณ (ref. github.com/applusform/WebViewFileUploadFix )
UnknownStack

@UnknownStack หากฉันกดปุ่มย้อนกลับแอปพลิเคชันจะปิดทุกที่เพื่อใช้รหัสนี้ในรหัสของคุณ .. สาธารณะบูลีน onKeyDown (int keyCode, เหตุการณ์ KeyEvent) {ถ้า ((keyCode == KeyEvent.KEYCODE_BACK) && this.webView.canGoBack ( )) {this.webView.goBack (); กลับจริง } คืนค่า super.onKeyDown (keyCode เหตุการณ์); }
sun y

12

สิ่งนี้ใช้ได้สำหรับฉัน ทำงานให้กับ Nougat และ Marshmallow ด้วย[ 2][3]

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getSimpleName();
    private final static int FCR = 1;
    WebView webView;
    private String mCM;
    private ValueCallback<Uri> mUM;
    private ValueCallback<Uri[]> mUMA;

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);

        if (Build.VERSION.SDK_INT >= 21) {
            Uri[] results = 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 = new Uri[]{Uri.parse(mCM)};
                        }
                    } else {
                        String dataString = intent.getDataString();
                        if (dataString != null) {
                            results = new Uri[]{Uri.parse(dataString)};
                        }
                    }
                }
            }
            mUMA.onReceiveValue(results);
            mUMA = null;
        } else {

            if (requestCode == FCR) {
                if (null == mUM) return;
                Uri result = intent == null || resultCode != RESULT_OK ? null : intent.getData();
                mUM.onReceiveValue(result);
                mUM = null;
            }
        }
    }

    @SuppressLint({"SetJavaScriptEnabled", "WrongViewCast"})
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (Build.VERSION.SDK_INT >= 23 && (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)) {
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA}, 1);
        }

        webView = (WebView) findViewById(R.id.ifView);
        assert webView != null;

        WebSettings webSettings = webView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setAllowFileAccess(true);

        if (Build.VERSION.SDK_INT >= 21) {
            webSettings.setMixedContentMode(0);
            webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
        } else if (Build.VERSION.SDK_INT >= 19) {
            webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
        } else if (Build.VERSION.SDK_INT < 19) {
            webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        }

        webView.setWebViewClient(new Callback());
        webView.loadUrl("https://infeeds.com/");
        webView.setWebChromeClient(new WebChromeClient() {

            //For Android 3.0+
            public void openFileChooser(ValueCallback<Uri> uploadMsg) {

                mUM = uploadMsg;
                Intent i = new Intent(Intent.ACTION_GET_CONTENT);
                i.addCategory(Intent.CATEGORY_OPENABLE);
                i.setType("*/*");
                MainActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), FCR);
            }

            // For Android 3.0+, above method not supported in some android 3+ versions, in such case we use this
            public void openFileChooser(ValueCallback uploadMsg, String acceptType) {

                mUM = uploadMsg;
                Intent i = new Intent(Intent.ACTION_GET_CONTENT);
                i.addCategory(Intent.CATEGORY_OPENABLE);
                i.setType("*/*");
                MainActivity.this.startActivityForResult(
                        Intent.createChooser(i, "File Browser"),
                        FCR);
            }

            //For Android 4.1+
            public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {

                mUM = uploadMsg;
                Intent i = new Intent(Intent.ACTION_GET_CONTENT);
                i.addCategory(Intent.CATEGORY_OPENABLE);
                i.setType("*/*");
                MainActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), MainActivity.FCR);
            }

            //For Android 5.0+
            public boolean onShowFileChooser(
                    WebView webView, ValueCallback<Uri[]> filePathCallback,
                    WebChromeClient.FileChooserParams fileChooserParams) {

                if (mUMA != null) {
                    mUMA.onReceiveValue(null);
                }

                mUMA = filePathCallback;
                Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                if (takePictureIntent.resolveActivity(MainActivity.this.getPackageManager()) != null) {

                    File photoFile = null;

                    try {
                        photoFile = createImageFile();
                        takePictureIntent.putExtra("PhotoPath", mCM);
                    } catch (IOException ex) {
                        Log.e(TAG, "Image file creation failed", ex);
                    }
                    if (photoFile != null) {
                        mCM = "file:" + photoFile.getAbsolutePath();
                        takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
                    } else {
                        takePictureIntent = null;
                    }
                }

                Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
                contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
                contentSelectionIntent.setType("*/*");
                Intent[] intentArray;

                if (takePictureIntent != null) {
                    intentArray = new Intent[]{takePictureIntent};
                } else {
                    intentArray = new Intent[0];
                }

                Intent chooserIntent = new 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
    private File createImageFile() throws IOException {

        @SuppressLint("SimpleDateFormat") String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String imageFileName = "img_" + timeStamp + "_";
        File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
        return File.createTempFile(imageFileName, ".jpg", storageDir);
    }

    @Override
    public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {

        if (event.getAction() == KeyEvent.ACTION_DOWN) {

            switch (keyCode) {
                case KeyEvent.KEYCODE_BACK:

                    if (webView.canGoBack()) {
                        webView.goBack();
                    } else {
                        finish();
                    }

                    return true;
            }
        }

        return super.onKeyDown(keyCode, event);
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }

    public class Callback extends WebViewClient {
        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
            Toast.makeText(getApplicationContext(), "Failed loading app!", Toast.LENGTH_SHORT).show();
        }
    }
}

11

ฉันพบว่าจำเป็นต้องกำหนดpublic void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture)ใน Android 4.1 จากนั้นฉันก็ทำตามวิธีแก้ปัญหาของ Michel Olivier


คุณช่วยอธิบายได้อย่างชัดเจนว่าฉันควรกำหนดวิธีนี้ที่ไหน และฉันควรใช้มันอย่างไร?
CAMOBAP

9

ฉันได้รับการจัดการจริงเพื่อให้ตัวเลือกไฟล์ปรากฏใน Kitkat เพื่อเลือกภาพและรับ filepath ในผลกิจกรรม แต่สิ่งเดียวที่ฉันไม่สามารถ "แก้ไข" (ทำให้การแก้ปัญหานี้) คือการป้อนข้อมูลที่กรอก ออกมาพร้อมกับข้อมูลไฟล์

ไม่มีใครรู้วิธีเข้าถึงฟิลด์อินพุตจากกิจกรรมหรือไม่? กำลังใช้ความคิดเห็นตัวอย่างนี้ เป็นเพียงชิ้นส่วนสุดท้ายนี้อิฐก้อนสุดท้ายในกำแพงที่ฉันต้องใส่ในสถานที่ที่เหมาะสม (tho ฉันสามารถเรียกอัพโหลดไฟล์ภาพโดยตรงจากรหัส

อัปเดต # 1

ฉันไม่ยอมใครง่ายๆ Android dev ดังนั้นฉันจะแสดงรหัสในระดับมือใหม่ ฉันกำลังสร้างกิจกรรมใหม่ในกิจกรรมที่มีอยู่แล้ว

ส่วนที่แสดงให้เห็น

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application android:label="TestApp">
 <activity android:name=".BrowseActivity"></activity>
</application>

กำลังสร้างคลาส BrowseActivity ของฉันจากคำตอบตัวอย่างนี้ อินสแตนซ์ WebChromeClient () โดยทั่วไปมีลักษณะเหมือนกันยกเว้นชิ้นส่วนสุดท้ายทริกเกอร์ส่วน UI ตัวเลือก ...

private final static int FILECHOOSER_RESULTCODE=1;  
private final static int KITKAT_RESULTCODE = 2;

...

// The new WebChromeClient() looks pretty much the same, except one piece...

WebChromeClient chromeClient = new WebChromeClient(){  
    // For Android 3.0+
    public void openFileChooser(ValueCallback<Uri> uploadMsg) { /* Default code */ }  

    // For Android 3.0+
    public void openFileChooser( ValueCallback uploadMsg, String acceptType ) { /* Default code */ }  

    //For Android 4.1, also default but it'll be as example
    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture){
        mUploadMessage = uploadMsg;
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);
        i.setType("*/*");
        BrowseActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), BrowseActivity.FILECHOOSER_RESULTCODE);

    }  

    // The new code
    public void showPicker( ValueCallback<Uri> uploadMsg ){  
        // Here is part of the issue, the uploadMsg is null since it is not triggered from Android
        mUploadMessage = uploadMsg; 
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);
        i.setType("*/*");
        BrowseActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), BrowseActivity.KITKAT_RESULTCODE);
    }}

และอีกหลายสิ่ง

web = new WebView(this);
// Notice this part, setting chromeClient as js interface is just lazy
web.getSettings().setJavaScriptEnabled(true);
web.addJavascriptInterface(chromeClient, "jsi" );
web.getSettings().setAllowFileAccess(true);
web.getSettings().setAllowContentAccess(true);
web.clearCache(true);
web.loadUrl( "http://as3breeze.com/upload.html" );
web.setWebViewClient(new myWebClient());
web.setWebChromeClient(chromeClient);


@Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) {  
  Log.d("Result", "("+requestCode+ ") - (" +resultCode  + ") - (" + intent + ") - " + mUploadMessage);  
    if (null == intent) return;  
    Uri result = null;  
    if(requestCode==FILECHOOSER_RESULTCODE)  
    {  
        Log.d("Result","Old android");  
        if (null == mUploadMessage) return;  
        result = intent == null || resultCode != RESULT_OK ? null  : intent.getData();  
        mUploadMessage.onReceiveValue(result);  
        mUploadMessage = null;  
    } else if (requestCode == KITKAT_RESULTCODE) {  
        Log.d("Result","Kitkat android");  
        result = intent.getData();  
        final int takeFlags = intent.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION  | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);  
        String path = getPath( this, result);  
        File selectedFile = new File(path); 
//I used you example with a bit of editing so thought i would share, here i added a method to upload the file to the webserver
File selectedFile = new File(path);  
            UploadFile(selectedFile);


        //mUploadMessage.onReceiveValue( Uri.parse(selectedFile.toString()) );  
        // Now we have the file but since mUploadMessage was null, it gets errors
    }  
}

 public void UploadFile(File selectedFile)
{
    Random rnd = new Random();
    String sName = "File" + rnd.nextInt(999999) + selectedFile.getAbsolutePath().substring(selectedFile.getAbsolutePath().lastIndexOf("."));
    UploadedFileName = sName;
    uploadFile = selectedFile;
    if (progressBar != null && progressBar.isShowing())
    {
        progressBar.dismiss();
    }
 // prepare for a progress bar dialog
    progressBar = new ProgressDialog(mContext);
    progressBar.setCancelable(true);
    progressBar.setMessage("Uploading File");
    progressBar.setProgressStyle(ProgressDialog.STYLE_SPINNER);            
    progressBar.show();
    new Thread() {

        public void run() 
        {
            int serverResponseCode;
            String serverResponseMessage;
            HttpURLConnection connection = null;
            DataOutputStream outputStream = null;
            DataInputStream inputStream = null;
            String pathToOurFile = uploadFile.getAbsolutePath();
            String urlServer = "http://serveraddress/Scripts/UploadHandler.php?name" + UploadedFileName;
            String lineEnd = "\r\n";
            String twoHyphens = "--";
            String boundary =  "*****";

            int bytesRead, bytesAvailable, bufferSize;
            byte[] buffer;
            int maxBufferSize = 1*1024*1024;

            try
            {
                FileInputStream fileInputStream = new FileInputStream(uploadFile);

                URL url = new URL(urlServer);
                connection = (HttpURLConnection) url.openConnection();
                Log.i("File", urlServer);

                // Allow Inputs &amp; Outputs.
                connection.setDoInput(true);
                connection.setDoOutput(true);
                connection.setUseCaches(false);

                // Set HTTP method to POST.
                connection.setRequestMethod("POST");

                connection.setRequestProperty("Connection", "Keep-Alive");
                connection.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary);
                Log.i("File", "Open conn");

                outputStream = new DataOutputStream( connection.getOutputStream() );

                outputStream.writeBytes(twoHyphens + boundary + lineEnd);
                outputStream.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\"" + pathToOurFile +"\"" + lineEnd);
                outputStream.writeBytes(lineEnd);
                Log.i("File", "write bytes");

                bytesAvailable = fileInputStream.available();
                bufferSize = Math.min(bytesAvailable, maxBufferSize);
                buffer = new byte[bufferSize];
                Log.i("File", "available: " + fileInputStream.available());

                // Read file
                bytesRead = fileInputStream.read(buffer, 0, bufferSize);

                Log.i("file", "Bytes Read: " + bytesRead);
                while (bytesRead > 0)
                {
                    outputStream.write(buffer, 0, bufferSize);
                    bytesAvailable = fileInputStream.available();
                    bufferSize = Math.min(bytesAvailable, maxBufferSize);
                    bytesRead = fileInputStream.read(buffer, 0, bufferSize);
                }

                outputStream.writeBytes(lineEnd);
                outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

                // Responses from the server (code and message)
                serverResponseCode = connection.getResponseCode();
                serverResponseMessage = connection.getResponseMessage();
                Log.i("file repsonse", serverResponseMessage);

//once the file is uploaded call a javascript function to verify the user wants to save the image
                progressBar.dismiss();
                runOnUiThread(new Runnable() 
                {

                    @Override
                    public void run() 
                    {
                        Log.i("start", "File name: " + UploadedFileName);
                        WebView myWebView = (WebView) findViewById(R.id.webview);
                        myWebView.loadUrl("javascript:CheckImage('" + UploadedFileName + "')");
                    }
                });


                fileInputStream.close();
                outputStream.flush();
                outputStream.close();
            }
            catch (Exception ex)
            {
                Log.i("exception", "Error: " + ex.toString());
            }               
        }
    }.start();

}

สุดท้ายรหัสเพิ่มเติมบางส่วนเพื่อรับเส้นทางไฟล์จริงรหัสที่พบใน SO, ive เพิ่ม url โพสต์ในความคิดเห็นเช่นกันเพื่อให้ผู้เขียนได้รับเครดิตสำหรับการทำงานของเขา

/**
 * Get a file path from a Uri. This will get the the path for Storage Access
 * Framework Documents, as well as the _data field for the MediaStore and
 * other file-based ContentProviders.
 *
 * @param context The context.
 * @param uri The Uri to query.
 * @author paulburke
 * @source https://stackoverflow.com/a/20559175
 */
@TargetApi(Build.VERSION_CODES.KITKAT)
public static String getPath(final Context context, final Uri uri) {

    final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;

    // DocumentProvider
    if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
        // ExternalStorageProvider
        if (isExternalStorageDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            if ("primary".equalsIgnoreCase(type)) {
                return Environment.getExternalStorageDirectory() + "/" + split[1];
            }

            // TODO handle non-primary volumes
        }
        // DownloadsProvider
        else if (isDownloadsDocument(uri)) {

            final String id = DocumentsContract.getDocumentId(uri);
            final Uri contentUri = ContentUris.withAppendedId(
                    Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));

            return getDataColumn(context, contentUri, null, null);
        }
        // MediaProvider
        else if (isMediaDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            Uri contentUri = null;
            if ("image".equals(type)) {
                contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            } else if ("video".equals(type)) {
                contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
            } else if ("audio".equals(type)) {
                contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
            }

            final String selection = "_id=?";
            final String[] selectionArgs = new String[] {
                    split[1]
            };

            return getDataColumn(context, contentUri, selection, selectionArgs);
        }
    }
    // MediaStore (and general)
    else if ("content".equalsIgnoreCase(uri.getScheme())) {
        return getDataColumn(context, uri, null, null);
    }
    // File
    else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
    }

    return null;
}

/**
 * Get the value of the data column for this Uri. This is useful for
 * MediaStore Uris, and other file-based ContentProviders.
 *
 * @param context The context.
 * @param uri The Uri to query.
 * @param selection (Optional) Filter used in the query.
 * @param selectionArgs (Optional) Selection arguments used in the query.
 * @return The value of the _data column, which is typically a file path.
 * @source https://stackoverflow.com/a/20559175
 */
public static String getDataColumn(Context context, Uri uri, String selection,
                                   String[] selectionArgs) {

    Cursor cursor = null;
    final String column = "_data";
    final String[] projection = {
            column
    };

    try {
        cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
                null);
        if (cursor != null && cursor.moveToFirst()) {
            final int column_index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(column_index);
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }
    return null;
}


/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is ExternalStorageProvider.
 * @source https://stackoverflow.com/a/20559175
 */
public static boolean isExternalStorageDocument(Uri uri) {
    return "com.android.externalstorage.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is DownloadsProvider.
 * @source https://stackoverflow.com/a/20559175
 */
public static boolean isDownloadsDocument(Uri uri) {
    return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is MediaProvider.
 * @source https://stackoverflow.com/a/20559175
 */
public static boolean isMediaDocument(Uri uri) {
    return "com.android.providers.media.documents".equals(uri.getAuthority());
}  

สุดท้ายหน้า HTML จำเป็นต้องเรียกใช้เมธอดใหม่ของ showPicker (เฉพาะเมื่อ A4.4)

<form id="form-upload" method="post" enctype="multipart/form-data">
    <input id="fileupload" name="fileupload" type="file" onclick="javascript:prepareForPicker();"/>
</form>
<script type="text/javascript">
function getAndroidVersion() {
    var ua = navigator.userAgent; 
    var match = ua.match(/Android\s([0-9\.]*)/);
    return match ? match[1] : false;
};
function prepareForPicker(){
    if(getAndroidVersion().indexOf("4.4") != -1){
        window.jsi.showPicker();
        return false;
    }
}

function CheckImage(name)
{
//Check to see if user wants to save I used some ajax to save the file if necesarry
}
</script>

ขออภัยที่ตอบช้าไม่มีการสาธิตการทำงานใด ๆ สำหรับอันนี้ นี่เป็นงานวิจัยธรรมดาในเวลานั้น ขอโทษ :(
Deko


6

2019: รหัสนี้ใช้ได้สำหรับฉัน (ทดสอบบน Androids 5 - 9)

package com.example.filechooser;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.net.http.SslError;
import android.os.Bundle;
import android.webkit.SslErrorHandler;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;


public class MainActivity extends Activity {

    // variables para manejar la subida de archivos
    private final static int FILECHOOSER_RESULTCODE = 1;
    private ValueCallback<Uri[]> mUploadMessage;

    // variable para manejar el navegador empotrado
    WebView mainWebView;


    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        // instanciamos el webview
        mainWebView = findViewById(R.id.main_web_view);

        // establecemos el cliente interno para que la navegacion no se salga de la aplicacion
        mainWebView.setWebViewClient(new MyWebViewClient());

        // establecemos el cliente chrome para seleccionar archivos
        mainWebView.setWebChromeClient(new MyWebChromeClient());

        // configuracion del webview
        mainWebView.getSettings().setJavaScriptEnabled(true);

        // cargamos la pagina
        mainWebView.loadUrl("https://example.com");
    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {

        // manejo de seleccion de archivo
        if (requestCode == FILECHOOSER_RESULTCODE) {

            if (null == mUploadMessage || intent == null || resultCode != RESULT_OK) {
                return;
            }

            Uri[] result = null;
            String dataString = intent.getDataString();

            if (dataString != null) {
                result = new Uri[]{ Uri.parse(dataString) };
            }

            mUploadMessage.onReceiveValue(result);
            mUploadMessage = null;
        }
    }


    // ====================
    // Web clients classes
    // ====================

    /**
     * Clase para configurar el webview
     */
    private class MyWebViewClient extends WebViewClient {

        // permite la navegacion dentro del webview
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }
    }


    /**
     * Clase para configurar el chrome client para que nos permita seleccionar archivos
     */
    private class MyWebChromeClient extends WebChromeClient {

        // maneja la accion de seleccionar archivos
        @Override
        public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {

            // asegurar que no existan callbacks
            if (mUploadMessage != null) {
                mUploadMessage.onReceiveValue(null);
            }

            mUploadMessage = filePathCallback;

            Intent i = new Intent(Intent.ACTION_GET_CONTENT);
            i.addCategory(Intent.CATEGORY_OPENABLE);
            i.setType("*/*"); // set MIME type to filter

            MainActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), MainActivity.FILECHOOSER_RESULTCODE );

            return true;
        }
    }

}

หวังว่าจะช่วยคุณได้


สำหรับวิธี onActivityResult มันบอกว่าโทรไปที่หายไปสุด ๆ
sumitkanoje

@sumitkanoje พยายามวางสายก่อนหน้าบล็อก if: super.onActivityResult (requestCode, resultCode, เจตนา);
sebasdev

5

พบโซลูชันที่เหมาะกับฉัน! เพิ่มอีกหนึ่งกฎในไฟล์proguard-android.txt:

-keepclassmembers class * extends android.webkit.WebChromeClient {
     public void openFileChooser(...);
}

คุณใช้ Android เวอร์ชันไหน
Punchlinern

4.4.4 CyanogemMode 11
ViliusK

5

วิธีแก้ปัญหา Kotlin สำหรับ Android 8:

private var mUploadMessage: ValueCallback<Uri>? = null
private var uploadMessage: ValueCallback<Array<Uri>>? = null

ค่าคงที่:

const val FILECHOOSER_RESULTCODE = 1
const val REQUEST_SELECT_FILE = 100

การตั้งค่า WebView:

webView.webChromeClient = object : WebChromeClient() {
        override fun onPermissionRequest(request: PermissionRequest?) {
            Log.d("MainActivity", "onPermissionRequest")
            requestPermission(request)
        }


        // For Android 3.0+
        fun openFileChooser(uploadMsg: ValueCallback<*>, acceptType: String) {
            mUploadMessage = uploadMsg as ValueCallback<Uri>
            val i = Intent(Intent.ACTION_GET_CONTENT)
            i.addCategory(Intent.CATEGORY_OPENABLE)
            i.type = "*/*"
            this@MainActivity.startActivityForResult(
                    Intent.createChooser(i, "File Browser"),
                    FILECHOOSER_RESULTCODE)
        }

        //For Android 4.1
        fun openFileChooser(uploadMsg: ValueCallback<Uri>, acceptType: String, capture: String) {
            mUploadMessage = uploadMsg
            val i = Intent(Intent.ACTION_GET_CONTENT)
            i.addCategory(Intent.CATEGORY_OPENABLE)
            i.type = "image/*"
            this@MainActivity.startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE)

        }

        protected fun openFileChooser(uploadMsg: ValueCallback<Uri>) {
            mUploadMessage = uploadMsg
            val intent = Intent(Intent.ACTION_GET_CONTENT)
            intent.addCategory(Intent.CATEGORY_OPENABLE)
            intent.type = "*/*"
            startActivityForResult(Intent.createChooser(intent, "File Chooser"), FILECHOOSER_RESULTCODE)
        }

        override fun onShowFileChooser(webView: WebView?, filePathCallback: ValueCallback<Array<Uri>>?, fileChooserParams: FileChooserParams?): Boolean {
            uploadMessage?.onReceiveValue(null)
            uploadMessage = null

            uploadMessage = filePathCallback

            val intent = fileChooserParams!!.createIntent()
            try {
                startActivityForResult(intent, REQUEST_SELECT_FILE)
            } catch (e: ActivityNotFoundException) {
                uploadMessage = null
                Toast.makeText(applicationContext, "Cannot Open File Chooser", Toast.LENGTH_LONG).show()
                return false
            }

            return true
        }

    }

และส่วนที่เกี่ยวกับศิลปะผลงาน:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        if (requestCode === REQUEST_SELECT_FILE) {
            if (uploadMessage == null)
                return
            print("result code = " + resultCode)
            var results: Array<Uri>? = WebChromeClient.FileChooserParams.parseResult(resultCode, data)
            uploadMessage?.onReceiveValue(results)
            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
        val result = if (intent == null || resultCode !== RESULT_OK) null else intent.data
        mUploadMessage?.onReceiveValue(result)
        mUploadMessage = null
    } else
        Toast.makeText(applicationContext, "Failed to Upload Image", Toast.LENGTH_LONG).show()
}

โปรดใส่ใจว่าตัวแปรเจตนาของเราเรียกว่า "ข้อมูล"


1
ขอบคุณ! ฉันจะรับเบียร์ให้คุณ
Rafael Ruiz Muñoz

ขอบคุณ! ทำงานร่วมกับ Android 10 ด้วย :)
Vegeta ZA

2

ขอบคุณสำหรับคำแนะนำของคุณ Pragna ปัญหาที่เกิดขึ้นจริง - มุมมองเว็บที่ไม่ได้นำเสนอให้ฉันกล่องโต้ตอบการอัปโหลดไฟล์ที่ฉันสามารถเลือกไฟล์ที่จะอัปโหลด ดังนั้นก่อนอื่นฉันต้องมีโซลูชันที่ช่วยให้ฉันสามารถแสดงกล่องโต้ตอบอัปโหลดไฟล์จากนั้นฉันสามารถอ้างอิงลิงก์ที่คุณแนะนำ
user741148

stackoverflow.com/questions/5617388/browse-button-requiredเมื่อดูลิงก์นี้
Android

ขอบคุณ 4 ข้อเสนอแนะของคุณ Pragna ไม่มีงาน ...จริง ๆ แล้วสิ่งหนึ่งที่ฉันสังเกตเห็นก็คือการเอาชนะเมธอด openFileChooser (ValueCallback <Uri>) ของ WebChromeClient ทำงานใน android 2.2 โดยการคลิกที่ฟิลด์ <input type = "file"> ใน UI ช่วยอำนวยความสะดวกในการเลือกไฟล์จาก แกลเลอรี่ แต่เดียวกันไม่ทำงานใน android 3.0 ... นั่น 4 ฉันคิดว่าลองอัปโหลดไฟล์ใน webview พร้อมแฟลชอัปโหลดไฟล์ แต่ใน android 3.0 emulator flash ไม่ได้ติดตั้งโดยค่าเริ่มต้นและติดตั้งแอปตลาดไม่พร้อมใช้งาน และในภาวะแทรกซ้อน ... สรุปปัญหาดูเหมือนจะเป็นไปไม่ได้กับ givens!
user741148

1

ใน KitKat คุณสามารถใช้การจัดเก็บข้อมูลการเข้ากรอบ

Storage Access Framework / การเขียนแอปไคลเอ็นต์


"อาจจะ"? คุณสามารถระบุบริบทเพิ่มเติมสำหรับโพสต์ของคุณได้ไหม กรุณาอ่านวิธีการตอบ
brasofilo

มีโค้ดตัวอย่างที่จะใช้ใน android 4.4.2 โดยใช้ webview หรือไม่?
BABU K

1

Webview - เดี่ยวและหลายไฟล์เลือก

คุณต้องการสองนาทีในการใช้รหัสนี้:

build.gradle

implementation 'com.github.angads25:filepicker:1.1.1'

รหัส java:

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.bivoiclient.utils.Constants;
import com.github.angads25.filepicker.controller.DialogSelectionListener;
import com.github.angads25.filepicker.model.DialogConfigs;
import com.github.angads25.filepicker.model.DialogProperties;
import com.github.angads25.filepicker.view.FilePickerDialog;

import java.io.File;

public class WebBrowserScreen extends Activity {

    private WebView webView;
    private ValueCallback<Uri[]> mUploadMessage;
    private FilePickerDialog dialog;
    private String LOG_TAG = "DREG";
    private Uri[] results;

    @SuppressLint("SetJavaScriptEnabled")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_complain);

        webView = findViewById(R.id.webview);
        WebSettings webSettings = webView.getSettings();
        webSettings.setAppCacheEnabled(true);
        webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
        webSettings.setJavaScriptEnabled(true);
        webSettings.setLoadWithOverviewMode(true);
        webSettings.setAllowFileAccess(true);
        webView.setWebViewClient(new PQClient());
        webView.setWebChromeClient(new PQChromeClient());
        if (Build.VERSION.SDK_INT >= 19) {
            webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
        } else {
            webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        }

        webView.loadUrl(Constants.COMPLAIN_URL);

    }

    private void openFileSelectionDialog() {

        if (null != dialog && dialog.isShowing()) {
            dialog.dismiss();
        }

        //Create a DialogProperties object.
        final DialogProperties properties = new DialogProperties();

        //Instantiate FilePickerDialog with Context and DialogProperties.
        dialog = new FilePickerDialog(WebBrowserScreen.this, properties);
        dialog.setTitle("Select a File");
        dialog.setPositiveBtnName("Select");
        dialog.setNegativeBtnName("Cancel");
        properties.selection_mode = DialogConfigs.MULTI_MODE; // for multiple files
//        properties.selection_mode = DialogConfigs.SINGLE_MODE; // for single file
        properties.selection_type = DialogConfigs.FILE_SELECT;

        //Method handle selected files.
        dialog.setDialogSelectionListener(new DialogSelectionListener() {
            @Override
            public void onSelectedFilePaths(String[] files) {
                results = new Uri[files.length];
                for (int i = 0; i < files.length; i++) {
                    String filePath = new File(files[i]).getAbsolutePath();
                    if (!filePath.startsWith("file://")) {
                        filePath = "file://" + filePath;
                    }
                    results[i] = Uri.parse(filePath);
                    Log.d(LOG_TAG, "file path: " + filePath);
                    Log.d(LOG_TAG, "file uri: " + String.valueOf(results[i]));
                }
                mUploadMessage.onReceiveValue(results);
                mUploadMessage = null;
            }
        });
        dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialogInterface) {
                if (null != mUploadMessage) {
                    if (null != results && results.length >= 1) {
                        mUploadMessage.onReceiveValue(results);
                    } else {
                        mUploadMessage.onReceiveValue(null);
                    }
                }
                mUploadMessage = null;
            }
        });
        dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
            @Override
            public void onDismiss(DialogInterface dialogInterface) {
                if (null != mUploadMessage) {
                    if (null != results && results.length >= 1) {
                        mUploadMessage.onReceiveValue(results);
                    } else {
                        mUploadMessage.onReceiveValue(null);
                    }
                }
                mUploadMessage = null;
            }
        });

        dialog.show();

    }

    public class PQChromeClient extends WebChromeClient {

        @Override
        public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
            // Double check that we don't have any existing callbacks
            if (mUploadMessage != null) {
                mUploadMessage.onReceiveValue(null);
            }
            mUploadMessage = filePathCallback;

            openFileSelectionDialog();

            return true;
        }

    }

    //Add this method to show Dialog when the required permission has been granted to the app.
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
        switch (requestCode) {
            case FilePickerDialog.EXTERNAL_READ_PERMISSION_GRANT: {
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    if (dialog != null) {
                        openFileSelectionDialog();
                    }
                } else {
                    //Permission has not been granted. Notify the user.
                    Toast.makeText(WebBrowserScreen.this, "Permission is Required for getting list of files", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }

    public boolean onKeyDown(int keyCode, KeyEvent event) {
        // Check if the key event was the Back button and if there's history
        if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) {
            webView.goBack();
            return true;
        }
        // If it wasn't the Back key or there's no web page history, bubble up to the default
        // system behavior (probably exit the activity)

        return super.onKeyDown(keyCode, event);
    }


    public class PQClient extends WebViewClient {
        ProgressBar progressDialog;

        public boolean shouldOverrideUrlLoading(WebView view, String url) {

            // If url contains mailto link then open Mail Intent
            if (url.contains("mailto:")) {

                // Could be cleverer and use a regex
                //Open links in new browser
                view.getContext().startActivity(
                        new Intent(Intent.ACTION_VIEW, Uri.parse(url)));

                // Here we can open new activity

                return true;

            } else {
                // Stay within this webview and load url
                view.loadUrl(url);
                return true;
            }
        }

        // Show loader on url load
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            // Then show progress  Dialog
            // in standard case YourActivity.this
            if (progressDialog == null) {
                progressDialog = findViewById(R.id.progressBar);
                progressDialog.setVisibility(View.VISIBLE);
            }
        }

        // Called when all page resources loaded
        public void onPageFinished(WebView view, String url) {
            webView.loadUrl("javascript:(function(){ " +
                    "document.getElementById('android-app').style.display='none';})()");

            try {
                // Close progressDialog
                progressDialog.setVisibility(View.GONE);
            } catch (Exception exception) {
                exception.printStackTrace();
            }
        }
    }

}

บรรทัดนี้แสดงข้อผิดพลาดในการนำเข้า com.bivoiclient.utils.Constants;
. Md Ashikur เราะห์มาน

ลบการนำเข้านี้และตั้ง URL ของคุณลงในนี้: webView.loadUrl ( " google.com" );
Ahamadullah Saikat

สวัสดี Ahamadullah Saikat สำหรับความพยายามดังกล่าวมันทำงานได้ตามธรรมเนียม ... ไม่ทำงานตามค่าเริ่มต้น หากผู้ใช้รายใดต้องการเปิดโดยใช้ตัวเลือกสิ่งที่แนบเริ่มต้นใน webview ว่าจะทำเช่นนั้นได้อย่างไร มันทำงานรอบ ๆ
Tarit Ray

0

ฉันใหม่สำหรับ Andriod และต่อสู้กับสิ่งนี้เช่นกัน ตาม Google คู่มืออ้างอิง WebView

ตามค่าเริ่มต้น WebView จะไม่มีวิดเจ็ตเหมือนเบราว์เซอร์ไม่เปิดใช้งานข้อผิดพลาดของ JavaScript และหน้าเว็บ หากเป้าหมายของคุณเพียงเพื่อแสดง HTML บางส่วนเป็นส่วนหนึ่งของ UI ของคุณอาจเป็นไปได้ ผู้ใช้ไม่จำเป็นต้องโต้ตอบกับหน้าเว็บเกินกว่าจะอ่านและหน้าเว็บไม่จำเป็นต้องโต้ตอบกับผู้ใช้ หากคุณต้องการเว็บเบราว์เซอร์เต็มรูปแบบจริงๆแล้วคุณอาจต้องการเรียกใช้แอปพลิเคชันเบราว์เซอร์ที่มี URL แสดงเจตนาแทนที่จะแสดงด้วย WebView

รหัสตัวอย่างฉันดำเนินการใน MainActvity.java

 Uri uri = Uri.parse("https://www.example.com");
 Intent intent = new Intent(Intent.ACTION_VIEW, uri);
 startActivity(intent);

excuted

package example.com.myapp;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.content.Intent;
import android.net.Uri;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Uri uri = Uri.parse("http://www.example.com/");
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        startActivity(intent);
        getSupportActionBar().hide();
    }}

0

ฉันค้นคว้าเกี่ยวกับเรื่องนี้เป็นเวลาเกือบหนึ่งเดือน ทุกอย่างล้มเหลว รหัสทั้งหมดที่เห็นในเว็บไซต์หลายแห่งใช้งานไม่ได้ แต่นี่คือทางออกที่ดีที่สุด

https://github.com/chiclaim/android-webview-upload-file

ขั้นตอน

1) คลิกที่โคลนหรือดาวน์โหลด

2) รับ FLE ซิปในไดเรกทอรีท้องถิ่นของคุณ

3) คลายซิปไฟล์ zip

4) เปิดสตูดิโอ Android

5) ไฟล์ไปที่ ----> เปิด ---> นำทางไปยังไดเรกทอรีที่คุณคลายซิปเนื้อหา

6) เปลี่ยน url เว็บที่ต้องการใน webView.loadUrl ("url hre ของคุณ"); ใน MainActivity.java

7) ใช้งานได้ดีกับเวอร์ชั่น Android studio 3.4.2

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