Описание:
Пишу сервис автозаполнения для Android.Необходимые учетные данные хранятся в PWA, доступ к которому осуществляется через веб-просмотр через интерфейс Javascript.При запросе учетных данных служба отправляет packageName через WebView в JS.Как только учетные данные готовы, JS отправляет учетные данные через WebView в службу.Между тем, Служба должна сохранить обратный вызов из onFillRequest таким образом, чтобы он оставался доступным при получении учетных данных на buildResponse.
Проблема:
В настоящее время я использую переменную currentCallback
для храненияПерезвоните.Не хорошее решение ИМО.Это работает для первого запроса, но когда я возвращаюсь в приложение, а затем снова на экран входа в систему, я получаю сообщение об ошибке выполнения.
Кажется, 1-й обратный вызов повторно используется, даже если он должен был быть перезаписан:
Using Callback: android.service.autofill.FillCallback@12dea01
Попытки решения
Я пытался использовать концепцию замыкания:
private lateinit var currentCallback : (FillResponse) -> Unit
override fun onFillRequest(...) {
...
currentCallback = callbackWrapper(callback)
...
}
private fun buildResponse (...){
...
currentCallback(fillResponse)
...
}
Другие понятия, такие как сопрограммы и потоки, похоже, применимы только для двунаправленных запросов к серверу.
Также приветствуются предложения по изменению структуры кода
Ресурсы:
Соответствующий код приложения:
class FreePassAutofillService : AutofillService() {
private lateinit var currentCallback : FillCallback
override fun onFillRequest(
request: FillRequest,
cancellationSignal: CancellationSignal,
callback: FillCallback
) {
// Get fields and package name
...
// If no fields found, abort
if (fields.isEmpty) {
callback.onSuccess(null)
return
}
// We are registering an observer (mMessageReceiver) to receive Intents
...
//set callback for asynchronous response
Log.d(TAG, "Setting Callback: $callback")
currentCallback = callback
Log.d(TAG, "Callback set to $currentCallback")
// Fetch user data asynchronously via WebView.
sendMessage(appName)
// perserve fields
currentParsedStructure = buildParsedStructure (fields)
}
private fun buildResponse (credentials: List<JsInterface.Credentials>){
// Add a dataset to the response
if (::currentParsedStructure.isInitialized && ::currentCallback.isInitialized) {
// Create the base response
val response = FillResponse.Builder()
// add save information to response if we want to save the fields
...
//
for (i in 0 until credentials.size) {
val username = credentials[i].username
val password = credentials[i].password
Log.d(TAG, "Username: $username, Password: $password")
//build Dataset
...
}
val fillResponse: FillResponse = response.build()
val callback : FillCallback = currentCallback
Log.d(TAG, "Using Callback: $callback")
callback.onSuccess(fillResponse)
} else {
//Something went wrong
}
}
}
1-й запрос
D/Free Pass Autofill Service:
Package name: com.discord
autofillable fields:{AUTOFILL_HINT_EMAIL_ADDRESS=1073741825, AUTOFILL_HINT_PASSWORD=1073741824}
Setting Callback: android.service.autofill.FillCallback@12dea01
Callback set to android.service.autofill.FillCallback@12dea01
D/JsInterface:
Sending Credentials: CredentialsList(datasets=[Credentials(username=filler, password=$l|r*gNH>8N<?,Gk, url=com.discord)])
D/Free Pass Autofill Service:
Username: filler, Password: $l|r*gNH>8N<?,Gk
Using Callback: android.service.autofill.FillCallback@12dea01
2-й запрос
D/Free Pass Autofill Service:
Package name: com.discord
autofillable fields:{AUTOFILL_HINT_EMAIL_ADDRESS=1073741825, AUTOFILL_HINT_PASSWORD=1073741824}
Setting Callback: android.service.autofill.FillCallback@b8e253d
Callback set to android.service.autofill.FillCallback@b8e253d
D/JsInterface:
Sending Credentials: CredentialsList(datasets=[Credentials(username=filler, password=$l|r*gNH>8N<?,Gk, url=com.discord)])
D/Free Pass Autofill Service:
Username: filler, Password: $l|r*gNH>8N<?,Gk
Using Callback: android.service.autofill.FillCallback@12dea01
Ошибка
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.freepass, PID: 3947
java.lang.IllegalStateException: Already called
at android.service.autofill.FillCallback.assertNotCalled(FillCallback.java:81)
at android.service.autofill.FillCallback.onSuccess(FillCallback.java:48)
at com.example.freepass.FreePassAutofillService.buildResponse(FreePassAutofillService.kt:117)
at com.example.freepass.FreePassAutofillService.access$buildResponse(FreePassAutofillService.kt:21)
at com.example.freepass.FreePassAutofillService$mMessageReceiver$1.onReceive(FreePassAutofillService.kt:301)
at android.support.v4.content.LocalBroadcastManager.executePendingBroadcasts(LocalBroadcastManager.java:313)
at android.support.v4.content.LocalBroadcastManager$1.handleMessage(LocalBroadcastManager.java:121)
at android.os.Handler.dispatchMessage(Handler.java:109)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:7539)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:524)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:958)