2019 Jul. 15.
MyJsch.java
- package your.package;
-
- import android.content.Context;
-
- 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.io.InputStream;
- import java.util.Collections;
- import java.util.Hashtable;
- import java.util.List;
-
- class MyJsch {
- private final String ServerIp;
- private final int Port;
- private final String User;
- private final String PassPhraseWord;
- private final String IdentityKeyPath;
- private final Context AppContext;
-
- /** Channel接続タイプ */
- private static final String CHANNEL_TYPE = "sftp";
-
- /*
- * コンストラクタ
- */
- MyJsch( final String ServerIp, final int Port, final String User, final String PassPhraseWord,
- final String IdentityKeyPath, final Context AppContext) {
- this.ServerIp = ServerIp;
- this.Port = Port;
- this.User = User;
- this.PassPhraseWord = PassPhraseWord;
- this.IdentityKeyPath = IdentityKeyPath;
- this.AppContext = AppContext;
- }
-
-
- /*
- * Sessionを開始
- */
- protected Session connectSession() throws JSchException {
- Session session = null;
-
- // android端末内の外部ストーリッジ確認
- List sdCardFilesDirPaths =
- SdCardDirPaths.getSdCardFilesDirPathListForLollipop( AppContext );
- Collections.sort(sdCardFilesDirPaths, new CompStringLength());
- String externalPath = sdCardFilesDirPaths.get(0);
- externalPath = externalPath.replaceAll("/Android.*$", "");
- final JSch jsch = new JSch();
- // クライアント側のknownHostsチェックを行わない
- Hashtable config = new Hashtable();
- config.put("StrictHostKeyChecking", "no");
- jsch.setConfig(config);
- // パスフレーズ・秘密鍵方式
- String privKeyFilePath = externalPath + "/" + IdentityKeyPath;
- File privKeyFile = new File(privKeyFilePath);
- if (privKeyFile.exists() ) {
- jsch.addIdentity(privKeyFilePath, PassPhraseWord);
- }
- // Session取得
- session = jsch.getSession(User, ServerIp, Port);
- // パスワード方式でも可とする
- session.setPassword(PassPhraseWord);
- final UserInfo userInfo = new SftpUserInfo();
- session.setUserInfo(userInfo);
- session.connect();
- return session;
- }
- /**
- * SFTPのChannelを開始
- *
- * @param session
- * 開始されたSession情報
- */
- protected ChannelSftp connectChannelSftp(final Session session)
- throws JSchException {
- final ChannelSftp channel = (ChannelSftp) session.openChannel(CHANNEL_TYPE);
- try {
- channel.connect();
- } catch (JSchException e) {
- return null;
- }
- return channel;
- }
- /**
- * Session・Channelの終了
- *
- * @param session
- * 開始されたSession情報
- * @param channels
- * 開始されたChannel情報.複数指定可能
- */
- protected 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;
- }
- }
- /**
- * ファイルアップロード
- *
- * @throws JSchException
- * Session・Channelの設定/接続エラー時に発生
- */
- public void putFile(ChannelSftp channel, InputStream inStream, String destPath)
- throws SftpException {
- /*
- * sftp通信を実行
- */
- 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 );
- channel.cd(destParentPath);
- channel.put( inStream, destFile);
- // confirm existance of destFile
- channel.lstat(destFile);
- }
- /*
- * サーバー上のファイルの削除
- * destFileNameFront文字列から始まるファイルを全て削除する
- */
- public void deleteFiles(ChannelSftp channel, String destFileNameFront) throws SftpException {
- channel.rm(destFileNameFront + "*");
- }
- }
SdCardDirPaths.java
- package your.package;
-
- import android.annotation.TargetApi;
- import android.content.Context;
- import android.os.Build;
- import android.os.Environment;
-
- import java.io.File;
- import java.util.ArrayList;
- import java.util.List;
-
- public class SdCardDirPaths {
-
- /**
- * SDカードのfilesディレクトリパスのリストを取得する。
- * Android5.0以上対応。
- *
- * @param context
- * @return SDカードのfilesディレクトリパスのリスト
- */
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- public static List getSdCardFilesDirPathListForLollipop(Context context) {
- List sdCardFilesDirPathList = new ArrayList<>();
- // getExternalFilesDirsはAndroid4.4から利用できるAPI。
- // filesディレクトリのリストを取得できる。
- File[] dirArr = context.getExternalFilesDirs(null);
- for (File dir : dirArr) {
- if (dir != null) {
- String path = dir.getAbsolutePath();
- // isExternalStorageRemovableはAndroid5.0から利用できるAPI。
- // 取り外し可能かどうか(SDカードかどうか)を判定している。
- if (Environment.isExternalStorageRemovable(dir)) {
- // 取り外し可能であればSDカード。
- // このパスをパスリストに加える
- if (!sdCardFilesDirPathList.contains(path)) {
- sdCardFilesDirPathList.add(path);
- }
- }
- }
- }
- return sdCardFilesDirPathList;
- }
- }
(利用例)
Send2ServerTask.java
- package your.package;
-
- import android.app.Activity;
- import android.content.Context;
- import android.os.AsyncTask;
- import android.widget.Toast;
-
- import com.jcraft.jsch.ChannelSftp;
- import com.jcraft.jsch.JSchException;
- import com.jcraft.jsch.Session;
- import com.jcraft.jsch.SftpException;
-
- import java.io.InputStream;
- import java.lang.ref.WeakReference;
- import java.util.HashMap;
- import java.util.Map;
-
- // 複数のファイルをSSH送信する
- public class Send2ServerTask extends AsyncTask {
- final String ServerIp = "SSH.SERVER.IP.ADDRESS";
- final int Port = 22;
- final String User = "SshLogInUser";
- final String IdentityKeyPath = "PRIVATE/KEY/FILE/PATH/IN/CLIENT/DEVICE";
- // if IdentityKeyPath is illegal, password authentication is used.
- final String DestParentPath = "SERVER/DIR/TO/BE/STORED";
- private WeakReference weakRef;
- private HashMap inStreamMap;
- final private String passPhrase;
- final private String fileNameFront;
- // SSH失敗時のファイル削除のためにファイル名共通文字列を保持
- // 複数の送信ファイルはいずれもfileNameFront文字列で始まるファイル名とすること
- private Listener listener;
- /*
- * constructor
- * inStreamMap 送信する複数ファイルのファイル名とインプットストリームをHashMapで渡す
- */
- Send2ServerTask(Activity parentActivity, HashMap inStreamMap,
- String passPhrase, String fileNameFront) {
- weakRef = new WeakReference<>(parentActivity);
- this.inStreamMap = new HashMap<>(inStreamMap);
- this.passPhrase = passPhrase;
- this.fileNameFront = fileNameFront;
- }
- @Override
- protected String doInBackground(Void... params) {
- MyJsch mJsch;
- Session sftpSession = null;
- ChannelSftp sftpChannel = null;
- Activity refActivity = weakRef.get();
- if (refActivity == null || refActivity.isFinishing()) {
- return null;
- }
- Context appContext = weakRef.get().getApplicationContext();
- // initialise Jsch
- mJsch = new MyJsch(ServerIp, Port, User, passPhrase, IdentityKeyPath, appContext);
- // connect session, channel
- try {
- sftpSession = mJsch.connectSession();
- sftpChannel = mJsch.connectChannelSftp( sftpSession );
- // upload
- int count = 0;
- for ( Map.Entry entry : inStreamMap.entrySet()) {
- // entry.getKey() entry.getValue()
- String destPath = DestParentPath + "/" + entry.getKey();
- try {
- mJsch.putFile(sftpChannel, entry.getValue(), destPath);
- } catch (SftpException e) {
- try {
- // このセッションでアップロードされたファイルをすべて削除する
- mJsch.deleteFiles(sftpChannel, fileNameFront);
- mJsch.disconnect( sftpSession, sftpChannel);
- return "Failed to upload files. count: " + count + ". " + destPath + " " + e.toString();
- } catch (SftpException e1) {
- mJsch.disconnect( sftpSession, sftpChannel);
- return "Failed to delete remote files. " + e1.toString();
- }
- }
- try {
- // take sleep between SFTP#puts
- Thread.sleep(500);
- } catch (InterruptedException e) {
- // このセッションでアップロードされたファイルをすべて削除する
- mJsch.deleteFiles(sftpChannel, fileNameFront);
- mJsch.disconnect( sftpSession, sftpChannel);
- return "Failed! sleep" + e.toString();
- }
- count++;
- }
- if ( count != inStreamMap.size()) {
- // このセッションでアップロードされたファイルをすべて削除する
- mJsch.deleteFiles(sftpChannel, fileNameFront);
- mJsch.disconnect( sftpSession, sftpChannel);
- return "Could not upload " + inStreamMap.size() + " files";
- }
- } catch (JSchException | SftpException e) {
- mJsch.disconnect( sftpSession, sftpChannel);
- return "connection failed. " + e.toString();
- } finally {
- // disconnect channel, session
- mJsch.disconnect( sftpSession, sftpChannel);
- }
- return "Succeeded. " + inStreamMap.size() + " files upload";
- }
- @Override
- protected void onPostExecute(String result) {
- super.onPostExecute(result);
- Activity refActivity = weakRef.get();
- if (refActivity == null || listener == null) {
- Toast.makeText(refActivity, "failed sending to server.", Toast.LENGTH_LONG).show();
- } else {
- if ( result.contains("Succeeded") ) {
- Toast.makeText(refActivity, result, Toast.LENGTH_SHORT).show();
- } else {
- Toast.makeText(refActivity, result, Toast.LENGTH_LONG).show();
- }
- listener.onSuccess(result);
- }
- return;
- }
- void setListener(Listener listener) {
- this.listener = listener;
- }
- interface Listener {
- void onSuccess(String str);
- }
- }
MyActivity.java
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_confirm_before_send);
- buttonOK = findViewById(R.id.buttonOK);
- setListeners();
- }
-
- /*
- * Send2ServerTaskへのリスナ
- * サーバーへのアップロード終了後に行う処理を記述
- */
- private Send2ServerTask.Listener createListener() {
- return new Send2ServerTask.Listener() {
- @Override
- public void onSuccess(String result) {
- deleteFiles();
- }
- };
- }
-
- protected void setListeners(){
- buttonOK.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- /*
- * HashMap SSHサーバーに送るデータ
- * String 送信先ファイルパス
- * InputStream 送信ファイルのインプットストリーム
- */
- HashMap dataMap = new HashMap<>();
- setData2dataMap(); // dataMapにSSH通信データをセットする
- setPassPhraseWord();
- setFileNameFront();
- /*
- * dataMapを保管サーバーに送る
- */
- send2serverTask = new Send2ServerTask(thisActivity, dataMap, passPhraseWord, fileNameFront);
- // Listenerを設定し、send2serverTaskを実行してdataMapを保管サーバーに送る
- send2serverTask.setListener(createListener());
- send2serverTask.execute();
- }
- });
- }