質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.03%

AndroidでOkHttpを使って自前サーバに画像をPOSTする方法

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,101
退会済みユーザー

退会済みユーザー

タイトルの通り, 自前のサーバ(node.js)にAndroidの端末からPOSTする方法についてです.  Android5.0.2の実機でデバッグしています.
以下にコードを載せますが,errorはMainActivity.javaの中で ERROR!!とコメントアウトしてる部分に java.io.FileNotFoundException: /storage/emulated/0/(ファイル名).jpg: open failed: EACCES (Permission denied) と出ます.

file = new File(mImagePath) の手前のImageViewには画像がセットされるので, 画像までのPathは間違っていないと思います.

よろしくお願いします.

MainActivity.java

protected void onActivityResult(int requestCode, int resultCode, Intent data){
        if(data == null){return;}
        switch(requestCode){
            case UPLOAD_PIC_CODE:
                mImagePath = getPath(data.getData());// get image path
                mImageView.setImageURI(data.getData());// show the image
                file = new File(mImagePath);

                new AsyncTask<Void, Void, String>(){
                    @Override
                    protected String doInBackground(Void... ImagePath) {
                        String result = null;

                        RequestBody requestBody = new MultipartBody.Builder()
                                .setType(MultipartBody.FORM)
                                .addFormDataPart("upName", file.getName(), RequestBody.create(MediaType.parse("image/*"), file))
                                .build();

                        Request request = new Request.Builder()// ERROR!!
                                .url(POST_URL)
                                .post(requestBody)
                                .build();

                        try{
                            okhttp3.Response response = client.newCall(request).execute();
                            result = response.body().string();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }

                        return result;
                    }
                }.execute();
                break;
        }// ERROR!!
    }


    public String getPath(Uri uri){
        String[] projection = {MediaStore.Images.Media.DATA};
        CursorLoader loader = new CursorLoader(getApplicationContext(), uri, projection, null, null, null);
        Cursor cursor = loader.loadInBackground();
        int column_index = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        return cursor.getString(column_index);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.upload_button:
                Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
                intent.setType("image/*");
                startActivityForResult(intent, UPLOAD_PIC_CODE);
                break;
        }
    }
(function() {
    var express = require('express');
    var app = express();
    var mime = require('mime');
    var crypto = require('crypto');
    var multer = require('multer');

    // option
    var storage = multer.diskStorage({
        destination: function(req, file, cb) {
            cb(null, './uploads'); // absolute path
        },
        filename: function(req, file, cb) {
            var revName = file.originalname; // get original name
            var imageType = file.mimetype; // get image type
            var imageName = revName.split('.');// split .
            console.log('split after is ' + imageName[0]);
            console.log('split after is ' + imageName[1]);
            crypto.pseudoRandomBytes(16, function(err, raw) {
                // cb(null, raw.toString('hex') + imageName[0] + '.' + mime.extension(file.mimetype));
                cb(null, imageName[0] + '.' + mime.extension(file.mimetype));
            });
        }
    });

    // set disk storage
    var upload = multer({
        storage: storage
    });

    app.post('/upload', upload.single('upName'), function(req, res) {
        // call option
        console.log('-----post function------');
        console.log(`originalname: ${req.file.originalname}`);
        console.log(`path: ${req.file.path}`);
        //res.send(JSON.stringify(req.file));
        res.json({'response': 'Get!'});
        //console.log('-----req-----');
        console.log(req.file);
    });

    app.get('/', function(req,res){
        res.end('node file upload');
    });


    app.use('/', express.static('.'));
    app.listen(3000);
    console.log('http://localhost:3000 is generated.');
})();

AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

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

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • dsuzuki

    2016/07/15 14:53

    パーミッション設定を確認するため、AndroidManifest.xmlの追記をお願いします。

    キャンセル

  • 退会済みユーザー

    退会済みユーザー

    2016/07/15 15:56

    追加しました.ご指摘ありがとうございます

    キャンセル

  • amay077

    2016/07/15 16:48

    例えば 「 file = new File(mImagePath);」以降の処理を行わない(コメントアウトする)と、画面(mImageView)に目的の画像が表示されるのでしょうか? このように「○○までは期待通り動いている」という情報があると、回答が得られやすいと思います。

    キャンセル

  • 退会済みユーザー

    退会済みユーザー

    2016/07/15 18:18

    なるほど.ありがとうございます.修正します

    キャンセル

回答 2

checkベストアンサー

0

mImageView.setImageURI(data.getData()) は成功していることから、 ストレージへのアクセス権限(READ_EXTERNAL_STORAGE)は正しく機能していると考えられます。

一方で、 FileNotFoundException... Permission denied が発生するということは、getPath(data.getData()) で得られるファイルパスに何らかの原因があると思います。

data.getData() は URI を返しますが、URI は常に「ファイルパス」を含むとは限りません。

画像の取得に ACTION_GET_CONTENT によるコンテントプロバイダを使用していますが、この場合も同じく「ファイルパス」を返さない場合があります。

によると、 

content://com.android.providers.media.documents/documents/image:234

のようなデータを返す場合がある模様です。

data.getData() や getPath(…) の実際のデータを文字列で出力して確認してみてください。
あるいは、 file = new File(mImagePath); の後で、 file.exists() は true を返しているか確認してみてください。

「ファイルパス」でない場合は、

の方法で、「ファイルパス」が取得できるようですので、合わせて確認してみてください。

mImageView.setImageURI(data.getData()) が正常に動作するのは、このメソッドが、「ファイルパス」以外の URI も正しく処理する機能を持っているからと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

Androidアプリの実行環境は、エミュレータでしょうか。
エミュレータの「設定」-「アプリ」で該当のアプリの「許可」項目を確認して下さい。
ストレージの項目がOffになっていないでしょうか。
パーミッションの設定で項目が追加され、エミュレータの設定から許可をOnにすることで利用できるようになります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/07/15 18:22

    実行環境は実機のAndroid 5.0.2ですね.その項目があるか確認してみます

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.03%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる