2019年5月2日木曜日

JAVA JSch SFTP AndroidクライアントからSSHサーバーへのファイル転送

2019 May. 03.
2019 May. 02.

https://qiita.com/nenokido2000/items/a00348c9f6a0f942773b より




MainActivity.java

package YOUR.PACKAGE.NAME;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {


    /** Channel接続タイプ */
    private static final String CHANNEL_TYPE = "sftp";

    private MyTask task;

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

        setContentView(R.layout.activity_main);

        /*
        final String ServerIP = "ServerIP";
        final int Port = PortNum;
        final String UserId = "USER";
        final String PassPhrase = "YOURPASSPHRASE";
        final String IdentityKeyPath = "YOUR/SECRET/FILE/PATH"; // Do not attach '/' at head of path
        final String SourcePath = "PATH/TO/SOURCE/FILE"; // Do not attach '/' at head of path
        final String DestPath = "PATH/TO/DEST/FILE";
        */

        final String ServerIP="";
        final int Port = ;
        final String UserId = "";
        final String PassPhrase = "";
        final String IdentityKeyPath = "";
        final String SourcePath = "";
        final String DestPath = "";

        Button button1= (Button) findViewById(R.id.button1);
        TextView textView1 = (TextView) findViewById(R.id.textView1);

        // タスクの生成
        task = new MyTask(ServerIP, Port, UserId, PassPhrase, IdentityKeyPath, SourcePath, DestPath,this);

        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                v.setEnabled(false);
                // 非同期処理を開始する
                task.execute();
            }
        });
    }
}


MyTask.java
package YOUR.PACKAGE.NAME;
import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.widget.TextView;

import com.jcraft.jsch.JSchException;

import java.lang.ref.WeakReference;

public class MyTask extends AsyncTask {
    private final String ServerIp;
    private final int Port;
    private final String User;
    private final String IdentityKeyPath;
    private final String PassPhrase;
    private final String SrcPath;
    private final String DestPath;

    private WeakReference weakReference;


    // constructor
    MyTask(final String ServerIp, final int Port, final String User,
                  final String PassPhrase, final String IdentityKeyPath, final String SrcPath,
                  final String DestPath, Context referenceContext) {
        super();

        // 呼び出し元へのweakReference
        weakReference = new WeakReference<>(referenceContext);

        this.ServerIp = ServerIp;
        this.Port = Port;
        this.User = User;
        this.PassPhrase = PassPhrase;
        this.IdentityKeyPath = IdentityKeyPath;
        this.SrcPath = SrcPath;
        this.DestPath = DestPath;
    }



    /**
     * バックグランドで行う処理
     */
    @Override
    protected String doInBackground(Void... value) {
        // startJsch
        MyJsch mJsch = new MyJsch( ServerIp, Port, User, PassPhrase, IdentityKeyPath, SrcPath,
                DestPath, weakReference.get());
        try {
            mJsch.putFile();
        } catch (JSchException e) {
            e.printStackTrace();
            return e.toString();
        }
        return "Success";
    }


    /**
     * バックグランド処理が完了し、UIスレッドに反映する
     */
    @Override
    protected void onPostExecute(String result) {

        // get a reference to the activity if it is still there
        Activity activity = (Activity) weakReference.get();
        if (activity == null || activity.isFinishing()) return;

        activity.findViewById(R.id.button1).setEnabled(true);
        TextView tv = activity.findViewById(R.id.textView1);
        tv.setText(result);
    }

}


MyJsch.java
package YOUR.PACKAGE.NAME;
import android.content.Context;
import android.util.Log;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import com.jcraft.jsch.UserInfo;

import java.io.File;
import java.util.Collections;
import java.util.List;

public class MyJsch {
    private final String ServerIp;
    private final int Port;
    private final String User;
    private final String PassPhrase;
    private final String IdentityKeyPath;
    private final String SrcPath;
    private final String DestPath;
    private Context activityContext;

    private String externalPath;

    /** Channel接続タイプ */
    private static final String CHANNEL_TYPE = "sftp";

    /**
     * コンストラクタ
     */
    MyJsch(final String ServerIp, final int Port, final String User, final String PassPhrase,
           final String IdentityKeyPath, final String SrcPath, final String DestPath,
           Context activityContext) {
        this.ServerIp = ServerIp;
        this.Port = Port;
        this.User = User;
        this.IdentityKeyPath = IdentityKeyPath;
        this.PassPhrase = PassPhrase;
        this.SrcPath = SrcPath;
        this.DestPath = DestPath;
        this.activityContext = activityContext;
    }


    /**
     * ファイルアップロード
     *
     * @throws JSchException
     *             Session・Channelの設定/接続エラー時に発生
     */
    public void putFile()
            throws JSchException {

        Session session = null;
        ChannelSftp channel = null;


        // 外部ストーリッジ確認
        List sdCardFilesDirPaths =
                SdCardDirPaths.getSdCardFilesDirPathListForLollipop( activityContext );
        Collections.sort(sdCardFilesDirPaths, new CompStringLength());
        for (String p : sdCardFilesDirPaths) {
            Log.d("My", "SDパスの1つ: " + p);
        }
        externalPath = sdCardFilesDirPaths.get(0);
        externalPath = externalPath.replaceAll("/Android.*$", "");
        Log.d("My", "SDパス: " + externalPath);

        // get sourcePath
        final String sourcePath = externalPath + "/" + SrcPath;
        Log.d("My", "sourcePath " + sourcePath );
        if ( new File(sourcePath).exists()) {
            Log.d("My", sourcePath + " exists.");
        } else {
            Log.d("My", sourcePath + " not exist.");
        }

        /*
         * sftp通信を実行
        */
        try {
            session = connectSession();
            channel = connectChannelSftp(session);

            String absoluteDestPath = channel.getHome() + "/" + DestPath;
            String destFile = new File(absoluteDestPath).getName();
            int numDestPath = absoluteDestPath.length();
            int numDestFile = destFile.length();
            String destParentPath = absoluteDestPath.substring( 0, numDestPath - numDestFile );

            Log.d("My", "absoluteDestPath is " + absoluteDestPath);
            Log.d("My", "destFile is " + destFile);
            Log.d("My", "destParentPath is " + destParentPath);
            Log.d("My", "current local directory is " + channel.lpwd());
            Log.d("My", "remote home directory is " + channel.getHome());

            channel.cd(destParentPath);
            channel.put(sourcePath, destFile);


            try {
                channel.lstat(destFile);
            } catch (SftpException e) {
                Log.d("My", DestPath + " does not exist.");
                Log.d("My", e.toString());
            }

        } catch (SftpException e) {
            Log.d("My",e.toString());
        } finally {
            disconnect(session, channel);
        }
    }

    /**
     * Sessionを開始
     */
    private Session connectSession()
            throws JSchException {

        final JSch jsch = new JSch();

        // 鍵追加
        String keyFilePath = externalPath + "/" + IdentityKeyPath;
        if ( new File(keyFilePath).exists()) {
            Log.d("My",  keyFilePath + " exists.");

        } else {
            Log.d("My",  keyFilePath + " not exist.");
        }

        jsch.addIdentity(keyFilePath, PassPhrase);

        // Session設定
        final Session session = jsch.getSession(User, ServerIp, Port);
        final UserInfo userInfo = new SftpUserInfo();

        // TODO 今回は使用しないがパスフレーズ等が必要な場合はUserInfoインスタンス経由で設定する

        session.setUserInfo(userInfo);

        session.connect();

        return session;
    }

    /**
     * SFTPのChannelを開始
     *
     * @param session
     *            開始されたSession情報
     */
    private ChannelSftp connectChannelSftp(final Session session)
            throws JSchException {
        final ChannelSftp channel = (ChannelSftp) session.openChannel(CHANNEL_TYPE);
        try {
            channel.connect();

        } catch (JSchException e) {
            Log.d("My",   e.toString());
        }
        return channel;
    }


    /**
     * Session・Channelの終了
     *
     * @param session
     *            開始されたSession情報
     * @param channels
     *            開始されたChannel情報.複数指定可能
     */
    private void disconnect(final Session session, final Channel... channels) {
        if (channels != null) {
            for (Channel c: channels ) {
                if (c != null) {
                    c.disconnect();
                }
            }
        }
        if (session != null) {
            session.disconnect();
        }
    }

    /**
     * SFTPに接続するユーザ情報を保持するクラス
     */
    private static class SftpUserInfo implements UserInfo {

        @Override
        public String getPassword() {
            return null;
        }

        @Override
        public boolean promptPassword(String arg0) {
            return true;
        }

        @Override
        public boolean promptPassphrase(String arg0) {
            return true;
        }

        @Override
        public boolean promptYesNo(String arg0) {
            return true;
        }

        @Override
        public void showMessage(String arg0) {
        }

        @Override
        public String getPassphrase() {
            return null;
        }
    }
}

0 件のコメント:

コメントを投稿