Я пытаюсь создать приложение для Android с возможностью подключения к указанному FTP-серверу на Java. Операция подключения была выполнена в FTPconnection
class, а сетевой вызов FTP был отделен от основного потока через FtpTask
реализация класса.
Экспериментальная реализация
Название проекта: FTPConnectionTest
FTPconnection
реализация классаpackage com.example.ftpconnectiontest; import android.util.Log; import java.io.IOException; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; import org.apache.commons.net.SocketClient; import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPReply; public class FTPconnection { private static final String FTPHostName = "Hostname"; private static final int FTPPort = 21; private static final String FTPUsername = "Username"; private static final String FTPPassword = "Password"; public FTPconnection() { } public FTPClient connectftp() { // Reference: https://stackoverflow.com/a/8761268/6667035 FTPClient ftp = new FTPClient(); try { // Reference: https://stackoverflow.com/a/55950845/6667035 // The argument of `FTPClient.connect` method is hostname, not URL. ftp.connect(FTPHostName, FTPPort); boolean status = ftp.login(FTPUsername, FTPPassword); if (status) { ftp.enterLocalPassiveMode(); ftp.setFileType(FTP.BINARY_FILE_TYPE); ftp.sendCommand("OPTS UTF8 ON"); } System.out.println("status : " + ftp.getStatus()); } catch (UnknownHostException ex) { ex.printStackTrace(); } catch (SocketException en) { en.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return ftp; } }
FtpTask
реализация класса// AsyncTask must be subclassed to be used. The subclass will override at least one method // `doInBackground(Params...)`, and most often will override a second one `onPostExecute(Result)` // Reference: https://developer.android.com/reference/android/os/AsyncTask?authuser=4 // Reference: https://stackoverflow.com/a/12447497/6667035 private class FtpTask extends AsyncTask<Void, Void, FTPClient> { // `doInBackground` invoked on the background thread immediately after `onPreExecute()` // finishes executing. This step is used to perform background computation // that can take a long time. The parameters of the asynchronous task are // passed to this step. The result of the computation must be returned by // this step and will be passed back to the last step. This step can also use // `publishProgress(Progress...)` to publish one or more units of progress. // These values are published on the UI thread, in the `onProgressUpdate(Progress...)` // step. protected FTPClient doInBackground(Void... args) { FTPconnection ftpConnect = new FTPconnection(); FTPClient ftp = ftpConnect.connectftp(); return ftp; } // `onPostExecute` invoked on the UI thread after the background computation finishes. // The result of the background computation is passed to this step as // a parameter. protected void onPostExecute(FTPClient result) { Log.v("FTPTask","FTP connection complete"); ftpClient = result; //Where ftpClient is a instance variable in the main activity Log.v("Boolean.toString(ftpClient.isConnected())", Boolean.toString(ftpClient.isConnected())); ShowToast(Boolean.toString(ftpClient.isConnected()), Toast.LENGTH_SHORT); } }
Настройка разрешений пользователя
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.ftpconnectiontest"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.FTPConnectionTest"> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> </manifest>
build.gradle
plugins { id 'com.android.application' } android { compileSdk 30 defaultConfig { applicationId "com.example.ftpconnectiontest" minSdk 26 targetSdk 30 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') // https://mvnrepository.com/artifact/commons-net/commons-net implementation group: 'commons-net', name: 'commons-net', version: '20030805.205232' implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.google.android.material:material:1.3.0' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' }
Полный код тестирования
MainActivity.java
выполнение:
package com.example.ftpconnectiontest;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import org.apache.commons.net.ftp.FTPClient;
public class MainActivity extends AppCompatActivity {
private FTPClient ftpClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new FtpTask().execute();
}
void ShowToast(String Text, int Duration)
{
Context context = getApplicationContext();
CharSequence text = Text;
int duration = Duration;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
}
// AsyncTask must be subclassed to be used. The subclass will override at least one method
// `doInBackground(Params...)`, and most often will override a second one `onPostExecute(Result)`
// Reference: https://developer.android.com/reference/android/os/AsyncTask?authuser=4
// Reference: https://stackoverflow.com/a/12447497/6667035
private class FtpTask extends AsyncTask<Void, Void, FTPClient> {
// `doInBackground` invoked on the background thread immediately after `onPreExecute()`
// finishes executing. This step is used to perform background computation
// that can take a long time. The parameters of the asynchronous task are
// passed to this step. The result of the computation must be returned by
// this step and will be passed back to the last step. This step can also use
// `publishProgress(Progress...)` to publish one or more units of progress.
// These values are published on the UI thread, in the `onProgressUpdate(Progress...)`
// step.
protected FTPClient doInBackground(Void... args) {
FTPconnection ftpConnect = new FTPconnection();
FTPClient ftp = ftpConnect.connectftp();
return ftp;
}
// `onPostExecute` invoked on the UI thread after the background computation finishes.
// The result of the background computation is passed to this step as
// a parameter.
protected void onPostExecute(FTPClient result) {
Log.v("FTPTask","FTP connection complete");
ftpClient = result;
//Where ftpClient is a instance variable in the main activity
Log.v("Boolean.toString(ftpClient.isConnected())", Boolean.toString(ftpClient.isConnected()));
ShowToast(Boolean.toString(ftpClient.isConnected()), Toast.LENGTH_SHORT);
}
}
}
Если есть какие-то улучшения, пожалуйста, дайте мне знать.