Как отключить автоматическое сканирование NFC на мобильных устройствах Samsung с помощью Flutter?Android

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Как отключить автоматическое сканирование NFC на мобильных устройствах Samsung с помощью Flutter?

Сообщение Anonymous »

Я создаю приложение Flutter, которое должно читать/записывать NDEF только тогда, когда пользователь нажимает кнопку. На Samsung (SM-S918B, Galaxy S23 Ultra и Galaxy Note10+) системная обработка Samsung иногда все еще «захватывает» тег (автоматическое чтение/автоматическая обработка пользовательского интерфейса/URL-адресов), даже когда мое приложение находится на переднем плане. Я хочу полностью сохранить контроль NFC в своем приложении, чтобы система ничего не обрабатывала автоматически. Это должно быть возможно, например. приложение «NFC Tools» делает это. Приложение никогда не теряет фокус, и «автоматическое считывание тегов» не отображается.
Стек:
  • Flutter
  • Пакеты: nfc_manager, nfc_manager_ndef, ndef_record
  • Устройства: Samsung SM-S918B (One UI/Android 14) или Samsung Galaxy
    Note10+
Что я пробовал (и все равно не работает)
  • Встроенный режим чтения (Kotlin) с включением «залипания»
Я включаю Android ReaderMode на уровне активности и оставляю его включенным, пока приложение видимо:

Код: Выделить всё

class MainActivity : FlutterActivity() {
private val CHANNEL = "de.mytagapp.app/nfc"
private var nfcAdapter: NfcAdapter? = null
private var readerModeSticky = false

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
nfcAdapter = NfcAdapter.getDefaultAdapter(this)
}

override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
.setMethodCallHandler { call, result ->
when (call.method) {
"enableReaderMode" -> {
readerModeSticky = true
enableReaderModeInternal()
result.success(true)
}
"disableReaderMode" -> {
readerModeSticky = false
disableReaderModeInternal()
result.success(true)
}
else -> result.notImplemented()
}
}
}

override fun onResume() {
super.onResume()
if (readerModeSticky) enableReaderModeInternal()
}

override fun onPause() {
super.onPause()
// disable when not visible
disableReaderModeInternal()
}

private fun enableReaderModeInternal() {
val flags =
NfcAdapter.FLAG_READER_NFC_A or
// NfcAdapter.FLAG_READER_NFC_V  // (tested on/off)
NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS or
NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK

// No-op callback; Flutter handles reads/writes.
nfcAdapter?.enableReaderMode(this, { /* no-op */ }, flags, null)
}

private fun disableReaderModeInternal() {
nfcAdapter?.disableReaderMode(this)
}
}
Я не добавляю фильтры намерений/технические фильтры NFC в манифест (чтобы избежать отправки намерений в систему или другие приложения).
Activity имеет launchMode="singleTop".
  • Глобальная «защита» на стороне Flutter
Я заключаю все приложение в виджет, который включает ReaderMode при инициализации и повторно включает его при каждом возобновлении:

Код: Выделить всё

class NfcReaderGuard extends StatefulWidget {
final Widget child;
const NfcReaderGuard({super.key, required this.child});
@override
State createState() => _NfcReaderGuardState();
}

class _NfcReaderGuardState extends State with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
NfcReaderMode.enable(); // MethodChannel -> enableReaderMode
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) NfcReaderMode.enable();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
NfcReaderMode.disable();
super.dispose();
}
@override
Widget build(BuildContext context) => widget.child;
}
  • Только сеансы, инициируемые пользователем
  • Я вызываю NfcManager.instance.startSession(...) только после того, как пользователь нажимает
    кнопку (чтение/запись), и останавливаю его сразу после этого.
  • Сначала я проверяю доступность.
  • Записи имеют формат RTD_TEXT; нет записей URL-адресов, которые могли бы предложить системе
    открыть браузер.
Проблема:
Несмотря на все вышеперечисленное, на устройстве Samsung система по-прежнему иногда автоматически обрабатывает тег (как будто мой ReaderMode не «владеет» им). Даже фокусировка на приложении (нажатие на пользовательский интерфейс) не всегда предотвращает появление автоматического чтения/обработчика. Чаще всего я наблюдаю это, когда приложение восстанавливает фокус или после короткого цикла выключения и включения экрана.
Вопросы к экспертам Samsung/NFC/Android/Flutter:
  • Переопределяет ли Samsung поведение ReaderMode? На устройствах AOSP я бы
    ожидал, что EnableReaderMode(...) с SKIP_NDEF_CHECK остановит
    проверку NDEF платформы/автоматический пользовательский интерфейс. Есть ли особенности Samsung,
    когда система по-прежнему отправляет сообщения своему собственному обработчику?
  • Я стреляю себе в ногу, смешивая EnableReaderMode(...)
    и nfc_manager.startSession(...)? Может ли nfc_manager внутренне
    переключить свою собственную диспетчеризацию чтения/переднего плана и случайно повторно включить
    системные настройки по умолчанию на Samsung?
  • Рекомендуете ли вы вообще не использовать nfc_manager.startSession и
    вместо этого выполнять обнаружение всех тегов в собственном onTagDiscovered, а затем пересылать
    байты во Flutter через MethodChannel?
  • Будет ли EnableForegroundDispatch(...) более надежным на Samsung, чем
    ReaderMode здесь? Если да, какую-либо минимальную настройку, которая сохраняет намерения в моей
    Активности и надежно предотвращает захват
    приложениями Samsung Wallet/Tag — не требуя от пользователей изменения настроек устройства?
  • Какие-либо специфичные для Samsung флаги или рекомендации, которые мне не хватает?
    - Дополнительные флаги чтения?

    - Проблемы со временем (например, повторное включение позже) обратный вызов жизненного цикла)?
    – Известные варианты поведения пользовательского интерфейса, требующие другого подхода?
  • Другие обходные пути, которые вы использовали в рабочей среде? Мои ограничения:
    - Мне нужно избегать всплывающих окон и автоматического открытия системы.
    - Чтение/запись должны происходить только при явном действии пользователя.
    - Я бы предпочел не просить пользователей отключать службы Samsung Wallet/Tag
    в настройках, так как это отключит чтение тегов в целом (так показывают
    мои тесты)
Возможные следующие шаги, которые я рассматриваю (обратная связь приветствуется)
  • Станьте полностью нативными для обнаружения: обработайте onTagDiscovered в Kotlin,
    разберите там NDEF (или просто передайте необработанные данные/байты) во Flutter; вообще не
    вызывайте nfc_manager.startSession.
  • Попробуйте Foreground Dispatch вместо ReaderMode и убедитесь, что фильтры
    разрешают обработку URL-адресов.
  • Регулируйте время повторного включения в onResume() (например, публикуйте небольшую задержку) на
    если Samsung делает что-то во время возобновления работы.
  • Дважды проверьте теги, используемые для тестирования (убедитесь, что они не содержат
    URL/записей, которые агрессивно обрабатывает Samsung; у меня только RTD_TEXT
    , но я проведу повторное тестирование с пустым/FORMAT).
Если у кого-нибудь есть известный рецепт для Samsung (One UI) для сохранения NFC строго внутри приложения — либо с помощью ReaderMode, либо с помощью ReaderMode или Foreground Dispatch — буду очень признателен за конкретные указатели или фрагменты кода. Спасибо!

Подробнее здесь: https://stackoverflow.com/questions/797 ... ng-flutter
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»