JQ Blog

Androidでカメラ&ギャラリーの使い方

はじめに


今回のinuckのアプリでファイルアップロードのためにカメラやギャラリーの機能を使って、Android側でも対応することになりましたので情報をまとめました。

説明


Android 4.4に変わってからWebviewはChromium基盤として変更されたため、WebviewにもMobile Chrome Browserと同じようなレベルのパフォーマンスを持って最新HTML5やCSS3のWeb標準をサポートし、V8 Javascript エンジンを乗せた最新バージョンに適用しました。
なので、Webviewのパフォーマンスについて色んな変更が発生され、ここで話すファイルアップロードについた部分も適用されました。 ここには4.4以外のバージョンをまとめます。

権限


AndroidManifest.xml

まず、Permissionを設定します。
カメラとギャラリーを使うためには
この三つが必要です。

1
2
3
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

この三つをAndroidManifestに入れます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="jp.inuck.inuckapp">
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>



    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:minSdkVersion="8"
        >
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service
            android:name=".MyFirebaseMessagingService">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT"/>
            </intent-filter>
        </service>
        <service
            android:name=".MyFirebaseInstanceIDService">
            <intent-filter>
                <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
            </intent-filter>
        </service>
    </application>

</manifest>

Android 6.0になってからPermissionについて変わりまして6.0の前まではAndroidManifestに設定したら勝手に権限をとることになったんですが、6.0からは直接確認しないと権限が取れないところがありましてそのセッティングは相当めんどくさいので
私の場合はTedPermissionというライブラリを使いました。
ライブラリを使いたいなら下のようにbundle.gradleに設定したら良いです。 Alt text

4.4以外 (Android Version < 3.0  /  3.0 <= Android Version < 4.1  /  4.1 <= Android Version < 4.4  /  Android Version 5.0+)



共通で使うメソッド


imageChooser()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
private void imageChooser() {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if (takePictureIntent.resolveActivity(getContext().getPackageManager()) != null) {
        // Create the File where the photo should go
        File photoFile = null;
        try {
            photoFile = createImageFile();
            takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath);
        } catch (IOException ex) {
            // Error occurred while creating the File
            Log.e(getClass().getName(), "Unable to create Image File", ex);
        }

        // Continue only if the File was successfully created
        if (photoFile != null) {
            mCameraPhotoPath = "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(TYPE_IMAGE);

    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, INPUT_FILE_REQUEST_CODE);
}


createImageFile()

1
2
3
4
5
6
7
8
9
10
11
12
13
private File createImageFile() throws IOException {
    // Create an image file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = "JPEG_" + timeStamp + "_";
    File storageDir = Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES);
    File imageFile = File.createTempFile(
            imageFileName,  /* prefix */
            ".jpg",         /* suffix */
            storageDir      /* directory */
    );
    return imageFile;
}


onActivityResult (int, int, Intent)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Override
public void onActivityResult (int requestCode, int resultCode, Intent data) {
    if (requestCode == INPUT_FILE_REQUEST_CODE && resultCode == getActivity().RESULT_OK) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            if (filePathCallbackLollipop == null) {
                super.onActivityResult(requestCode, resultCode, data);
                return;
            }
            Uri[] results = new Uri[]{getResultUri(data)};

            filePathCallbackLollipop.onReceiveValue(results);
            filePathCallbackLollipop = null;
        } else {

            if (filePathCallbackNormal == null) {
                super.onActivityResult(requestCode, resultCode, data);
                return;
            }
            Uri result = getResultUri(data);

            Log.d(getClass().getName(), "openFileChooser : "+result);
            filePathCallbackNormal.onReceiveValue(result);
            filePathCallbackNormal = null;
        }
    } else {
        if (mFilePathCallback != null) mFilePathCallback.onReceiveValue(null);
        if (filePathCallbackNormal != null) filePathCallbackNormal.onReceiveValue(null);
        mFilePathCallback = null;
        filePathCallbackNormal = null;
        super.onActivityResult(requestCode, resultCode, data);
    }
}


getResultUri(Intent)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private Uri getResultUri(Intent data) {
    Uri result = null;
    if(data == null || TextUtils.isEmpty(data.getDataString())) {
        // If there is not data, then we may have taken a photo
        if(mCameraPhotoPath != null) {
            result = Uri.parse(mCameraPhotoPath);
        }
    } else {
        String filePath = "";
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            filePath = data.getDataString();
        } else {
            filePath = "file:" + RealPathUtil.getRealPath(getContext(), data.getData());
        }
        result = Uri.parse(filePath);
    }

    return result;
}


バージョン別


1. Android Version 5.0+

1
2
3
4
5
6
7
8
9
10
public boolean onShowFileChooser(WebView webView,
                                 ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
    System.out.println("WebViewActivity A>5, OS Version : " + Build.VERSION.SDK_INT + "\t onSFC(WV,VCUB,FCP), n=3");
    if (filePathCallbackLollipop != null) {
        filePathCallbackLollipop.onReceiveValue(null);
    }
    filePathCallbackLollipop = filePathCallback;
    imageChooser();
    return true;
}


2. 4.1 <= Android Version < 4.4

1
2
3
4
5
public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType, String capture) {
    Log.d(getClass().getName(), "openFileChooser : "+acceptType+"/"+capture);
    filePathCallbackNormal = uploadFile;
    imageChooser();
}


3. 3.0 <= Android Version < 4.1

1
2
3
4
5
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
    //System.out.println("WebViewActivity 3<A<4.1, OS Version : " + Build.VERSION.SDK_INT + "\t openFC(VCU,aT), n=2");
    filePathCallbackNormal = uploadFile;
    imageChooser();
}


4. Android Version < 3.0

1
2
3
4
5
6
7
8
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
    //System.out.println("WebViewActivity OS Version : " + Build.VERSION.SDK_INT + "\t openFC(VCU), n=1");
    filePathCallbackNormal = uploadMsg;
    Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType(TYPE_IMAGE);
    startActivityForResult(intent, INPUT_FILE_REQUEST_CODE);
}


テスト




1. Android 6.0



2. Android 5.1



3. Android 4.2