Skip to content

Commit a1a2a89

Browse files
authored
Merge pull request #77 from gree/experimental/android_input_type_file
[Experimental] WebChromeClient for <input type="file">
2 parents f7a59cf + 21c39ad commit a1a2a89

File tree

3 files changed

+174
-3
lines changed

3 files changed

+174
-3
lines changed

plugins/Android/project.properties

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# This file is automatically generated by Android Tools.
2+
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3+
#
4+
# This file must be checked in Version Control Systems.
5+
#
6+
# To customize properties used by the Ant build system use,
7+
# "ant.properties", and override values to adapt the script to your
8+
# project structure.
9+
android.library=true
10+
11+
# Project target.
12+
target=android-23

plugins/Android/src/net/gree/unitywebview/CWebViewPlugin.java

Lines changed: 160 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
package net.gree.unitywebview;
2323

2424
import android.app.Activity;
25+
import android.app.Fragment;
2526
import android.content.Context;
2627
import android.content.Intent;
2728
import android.content.pm.ApplicationInfo;
@@ -31,6 +32,9 @@
3132
import android.graphics.Point;
3233
import android.net.Uri;
3334
import android.os.Build;
35+
import android.os.Environment;
36+
import android.provider.MediaStore;
37+
import android.util.Log;
3438
import android.view.Gravity;
3539
import android.view.View;
3640
import android.view.ViewGroup.LayoutParams;
@@ -49,12 +53,16 @@
4953
import android.webkit.CookieSyncManager;
5054
import android.widget.FrameLayout;
5155
import android.webkit.PermissionRequest;
56+
import android.webkit.ValueCallback;
5257
// import android.support.v4.app.ActivityCompat;
53-
// import android.util.Log;
5458

59+
import java.io.File;
60+
import java.io.IOException;
5561
import java.net.HttpURLConnection;
5662
import java.net.URL;
5763
import java.net.URLEncoder;
64+
import java.text.SimpleDateFormat;
65+
import java.util.Date;
5866
import java.util.HashMap;
5967
import java.util.Hashtable;
6068
import java.util.List;
@@ -89,7 +97,7 @@ public void call(final String method, final String message) {
8997
}
9098
}
9199

92-
public class CWebViewPlugin {
100+
public class CWebViewPlugin extends Fragment {
93101
private static FrameLayout layout = null;
94102
private WebView mWebView;
95103
private OnGlobalLayoutListener mGlobalLayoutListener;
@@ -103,7 +111,69 @@ public class CWebViewPlugin {
103111
private Pattern mAllowRegex;
104112
private Pattern mDenyRegex;
105113

114+
private static final int INPUT_FILE_REQUEST_CODE = 1;
115+
private ValueCallback<Uri> mUploadMessage;
116+
private ValueCallback<Uri[]> mFilePathCallback;
117+
private String mCameraPhotoPath;
118+
106119
public CWebViewPlugin() {
120+
final Activity a = UnityPlayer.currentActivity;
121+
final CWebViewPlugin self = this;
122+
a.runOnUiThread(new Runnable() {public void run() {
123+
a
124+
.getFragmentManager()
125+
.beginTransaction()
126+
.add(0, self, "CWebViewPlugin")
127+
.commit();
128+
}});
129+
}
130+
131+
@Override
132+
public void onActivityResult(int requestCode, int resultCode, Intent data) {
133+
if (requestCode != INPUT_FILE_REQUEST_CODE) {
134+
super.onActivityResult(requestCode, resultCode, data);
135+
return;
136+
}
137+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
138+
if (mFilePathCallback == null) {
139+
super.onActivityResult(requestCode, resultCode, data);
140+
return;
141+
}
142+
Uri[] results = null;
143+
// Check that the response is a good one
144+
if (resultCode == Activity.RESULT_OK) {
145+
if (data == null) {
146+
if (mCameraPhotoPath != null) {
147+
results = new Uri[] { Uri.parse(mCameraPhotoPath) };
148+
}
149+
} else {
150+
String dataString = data.getDataString();
151+
// cf. https://www.petitmonte.com/java/android_webview_camera.html
152+
if (dataString == null) {
153+
if (mCameraPhotoPath != null) {
154+
results = new Uri[] { Uri.parse(mCameraPhotoPath) };
155+
}
156+
} else {
157+
results = new Uri[] { Uri.parse(dataString) };
158+
}
159+
}
160+
}
161+
mFilePathCallback.onReceiveValue(results);
162+
mFilePathCallback = null;
163+
} else {
164+
if (mUploadMessage == null) {
165+
super.onActivityResult(requestCode, resultCode, data);
166+
return;
167+
}
168+
Uri result = null;
169+
if (resultCode == Activity.RESULT_OK) {
170+
if (data != null) {
171+
result = data.getData();
172+
}
173+
}
174+
mUploadMessage.onReceiveValue(result);
175+
mUploadMessage = null;
176+
}
107177
}
108178

109179
public static boolean IsWebViewAvailable() {
@@ -245,6 +315,93 @@ public boolean onJsPrompt(WebView view, String url, String message, String defau
245315
public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) {
246316
callback.invoke(origin, true, false);
247317
}
318+
319+
// For Android < 3.0 (won't work because we cannot utilize FragmentActivity)
320+
// public void openFileChooser(ValueCallback<Uri> uploadFile) {
321+
// openFileChooser(uploadFile, "");
322+
// }
323+
324+
// For 3.0 <= Android < 4.1
325+
public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType) {
326+
openFileChooser(uploadFile, acceptType, "");
327+
}
328+
329+
// For 4.1 <= Android < 5.0
330+
public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType, String capture) {
331+
if (mUploadMessage != null) {
332+
mUploadMessage.onReceiveValue(null);
333+
}
334+
mUploadMessage = uploadFile;
335+
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
336+
intent.addCategory(Intent.CATEGORY_OPENABLE);
337+
intent.setType("*/*");
338+
startActivityForResult(intent, INPUT_FILE_REQUEST_CODE);
339+
}
340+
341+
// For Android 5.0+
342+
@Override
343+
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
344+
// cf. https://github.com/googlearchive/chromium-webview-samples/blob/master/input-file-example/app/src/main/java/inputfilesample/android/chrome/google/com/inputfilesample/MainFragment.java
345+
if (mFilePathCallback != null) {
346+
mFilePathCallback.onReceiveValue(null);
347+
}
348+
mFilePathCallback = filePathCallback;
349+
350+
mCameraPhotoPath = null;
351+
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
352+
if (takePictureIntent.resolveActivity(getActivity().getPackageManager()) != null) {
353+
// Create the File where the photo should go
354+
File photoFile = null;
355+
try {
356+
photoFile = createImageFile();
357+
takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath);
358+
} catch (IOException ex) {
359+
// Error occurred while creating the File
360+
Log.e("CWebViewPlugin", "Unable to create Image File", ex);
361+
}
362+
// Continue only if the File was successfully created
363+
if (photoFile != null) {
364+
mCameraPhotoPath = "file:" + photoFile.getAbsolutePath();
365+
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
366+
Uri.fromFile(photoFile));
367+
} else {
368+
takePictureIntent = null;
369+
}
370+
}
371+
372+
373+
Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
374+
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
375+
contentSelectionIntent.setType("*/*");
376+
377+
Intent[] intentArray;
378+
if(takePictureIntent != null) {
379+
intentArray = new Intent[]{takePictureIntent};
380+
} else {
381+
intentArray = new Intent[0];
382+
}
383+
384+
Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
385+
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
386+
// chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");
387+
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
388+
389+
startActivityForResult(chooserIntent, INPUT_FILE_REQUEST_CODE);
390+
391+
return true;
392+
}
393+
394+
private File createImageFile() throws IOException {
395+
// Create an image file name
396+
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
397+
String imageFileName = "JPEG_" + timeStamp + "_";
398+
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
399+
File imageFile = File.createTempFile(imageFileName, /* prefix */
400+
".jpg", /* suffix */
401+
storageDir /* directory */
402+
);
403+
return imageFile;
404+
}
248405
});
249406

250407
mWebViewPlugin = new CWebViewPluginInterface(self, gameObject);
@@ -328,6 +485,7 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) {
328485
}
329486
if (url.startsWith("http://") || url.startsWith("https://")
330487
|| url.startsWith("file://") || url.startsWith("javascript:")) {
488+
mWebViewPlugin.call("CallOnStarted", url);
331489
// Let webview handle the URL
332490
return false;
333491
} else if (url.startsWith("unity:")) {

sample/Assets/StreamingAssets/sample.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ <h1>Hello Unity WebView!</h1>
3131
<p><a href="javascript:void(0)" onclick="Unity.call('anchor');">[Send Message!]</a></p>
3232
<form method="get" action="form">
3333
<input id="input1" type="text" value="hoge" name="msg"/>
34-
<input type="submit" value="Send Message!" onclick="Unity.call('form?msg=' + document.getElementById('input1').value); return false;"/>
34+
<input type="submit" value="Send Message!" onclick="Unity.call('form?msg=' + document.getElementById('input1').value); return false;"/><br/>
35+
<input type="file" name="datafile"/>
3536
</form>
3637
</body>
3738
</html>

0 commit comments

Comments
 (0)