Я пытаюсь создать сервер внутри приложения android. Идея состоит в том, чтобы создать локальную точку доступа из самого телефона и запустить HTTP-сервер. Покажите пользователям инструкции по подключению к указанной точке доступа. Затем URL-адрес, который при посещении автоматически загружает файл с телефона.
Серверный поток
class Server(private val filePath: File): Thread() {
override fun run() {
val file = File(filePath, "test.txt")
file.writeText("testing file")
val server = embeddedServer(Netty, 8080) {
routing {
get("/") {
call.respondText { "Works" }
}
get("/files") {
call.respondFile(file, configure = {
this.setProperty(AttributeKey("Content-Disposition"), "attachment; filename=\"test.txt\"")
})
}
}
}
server.start(wait = true)
}
}
Локальная настройка Hotstop
val mWifiManager = baseContext.getSystemService(Context.WIFI_SERVICE) as WifiManager?
mWifiManager?.startLocalOnlyHotspot(object : WifiManager.LocalOnlyHotspotCallback() {
override fun onStarted(reservation: WifiManager.LocalOnlyHotspotReservation?) {
super.onStarted(reservation)
val wifiConfiguration = reservation?.wifiConfiguration
if (wifiConfiguration != null) {
Log.d("testing", wifiConfiguration.preSharedKey)
}
}
override fun onStopped() {
Toast.makeText(baseContext, "STOP", Toast.LENGTH_LONG).show()
super.onStopped()
}
override fun onFailed(reason: Int) {
Toast.makeText(baseContext, "FAIL", Toast.LENGTH_LONG).show()
super.onFailed(reason)
}
}, Handler())
gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
defaultConfig {
applicationId "com.extermeprogramming.servertest"
minSdkVersion 26
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
packagingOptions {
pickFirst "META-INF/io.netty.versions.properties"
exclude 'META-INF/INDEX.LIST'
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.0'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
// Ktor, HTTP SERVER
ext.ktor_version = '1.3.2'
implementation "io.ktor:ktor-server-core:$ktor_version"
implementation "io.ktor:ktor-server-netty:$ktor_version"
implementation "org.slf4j:slf4j-simple:1.7.9"
}
AndroidManifes
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.extermeprogramming.servertest" >
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<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/AppTheme" >
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.extermeprogramming.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/paths" />
</provider>
<activity android:name=".MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Когда сервер и точка доступа включаются в первый раз, запрос URL-адреса 192.169.43.1:8080/files завершается ошибкой, и точка доступа выключается без вызова каких-либо обратных вызовов ( onStopped, onFailed). Когда точка доступа снова включена, все работает, как ожидалось, и загрузка файла происходит без проблем, а точка доступа остается включенной.
Единственная ошибка, выдаваемая Ktor, - Call execution has been cancelled
. Изменение порядка шагов, сначала включение точки доступа, а затем сервера, приводит к тому же исключению. Я думаю, что есть некоторая конфигурация либо в Ktor, либо в Hotspot, которая исправит эту проблему, потому что после исключения, когда Hotspot снова включается, все работает.