Android/NFC: получить тег в onCreate() без нового намерения

Я работаю над NFC-приложением. Чтобы запустить свое приложение, я использую тег NDEF с записью AAR NDEF внутри.

Это прекрасно работает. Но теперь я хочу прочитать содержимое тега непосредственно в приложении. Как я могу это сделать?

(Это уже работает, когда я снимаю метку с телефона и снова касаюсь ее, но я хочу исключить этот шаг.)

Обновление: некоторые подробности Хорошо, чтобы было понятнее, вот некоторые части моего текущего кода.

private NfcAdapter nfcAdapter;
private static final int PENDING_INTENT_TECH_DISCOVERED = 1;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_l);
    text_output = (TextView) findViewById(R.id.textView2);

    NfcAdapter adapter = ((NfcManager) getSystemService(Context.NFC_SERVICE))
            .getDefaultAdapter();       
}

@Override
public void onResume() {
    super.onResume();

    nfcAdapter = ((NfcManager) this.getSystemService(Context.NFC_SERVICE))
            .getDefaultAdapter();

    PendingIntent pi = createPendingResult(PENDING_INTENT_TECH_DISCOVERED,
            new Intent(), 0);

    nfcAdapter.enableForegroundDispatch(this, pi,
            new IntentFilter[] { new IntentFilter(
                    NfcAdapter.ACTION_TECH_DISCOVERED) }, new String[][] {
                    new String[] { "android.nfc.tech.NdefFormatable" },
                    new String[] { "android.nfc.tech.Ndef" } });
} 

@Override
public void onPause() {
    super.onPause();
    nfcAdapter.disableForegroundDispatch(this);
}

@Override
protected void onActivityResult(int requestCode, int resultCode,
        final Intent data) {
    switch (requestCode) {
    case PENDING_INTENT_TECH_DISCOVERED:
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                doTagOperation(data);
            }
        };
        new Thread(runnable).start();

        break;
    }
}

private void doTagOperation(Intent data) {

    try {           
        String action = data.getAction();
        if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {

            Tag tag = data.getParcelableExtra(NfcAdapter.EXTRA_TAG);                                
            Ndef ndefTag = Ndef.get(tag);
        }
    } catch (Exception ex) {
                ...
    }
}

Чтобы запустить приложение, я использую AAR-NDEF-Record для тега, который можно создать следующим образом: NdefRecord ndr = NdefRecord.createApplicationRecord("com.example.something");

Итак, что я хочу: коснитесь тега, когда приложение не запущено, приложение запускается (уже работает), а затем оно должно напрямую читать тег без необходимости отодвигать телефон от тега и снова касаться его.


person Manuel    schedule 16.01.2014    source источник
comment
Было бы полезно, если бы вы опубликовали свой текущий код, возможно, метод onCreate(), который, по вашим словам, уже работает. Спасибо   -  person brwngrldev    schedule 16.01.2014


Ответы (2)


Если вы хотите получать намерение обнаружения NDEF в начале своей деятельности, вам необходимо добавить фильтр намерений, который срабатывает в сообщении NDEF тега, в манифест вашего приложения:

<activity ... >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>

Я думаю, у вас уже есть вышеперечисленное, поэтому вам нужно будет добавить фильтр намерений NDEF:

    <intent-filter>
        <action android:name="android.nfc.action.NDEF_DISCOVERED" />
        <category android:name="android.intent.category.DEFAULT" />

Вы можете использовать любой триггер на основе URI:

        <data android:scheme="http" android:host="mroland.at" android:pathPrefix="/test" />

Или схема на основе MIME:

        <data android:mimeType="application/vnd.mroland.test" />

Или, если вы хотите получить обнаруженное намерение NDEF для тега, содержащего только AAR (должен признать, что я никогда не проверял это, поэтому я только предполагаю, что это должно работать):

        <data android:scheme="vnd.android.nfc" android:host="ext"
              android:pathPrefix="/android.com:pkg" />

Но вы должны использовать один из них. (По крайней мере, на большинстве устройств это необходимо. Некоторые устройства/версии Android будут принимать фильтр намерений даже без элемента data.)

    </intent-filter>
</activity>

Затем вы можете получить намерение в onCreate(), onStart(), onResume() или где угодно, используя метод getIntent().

Обратите внимание: если вы не добавите фильтр намерений для NDEF_DISCOVERED в свой манифест, сообщение NDEF с AAR для вашего приложения приведет к тому, что действие намерения MAIN с категорией LAUNCHER будет передано вашему первому действию. который объявляет такой фильтр намерений. В этом случае вы не получите сообщение NDEF. Поэтому, если вы хотите получать сообщение NDEF, вам необходимо объявить фильтр намерений для NDEF_DISCOVERED. В этом случае вы можете выбрать, какое действие запускает AAR, установив фильтр намерений NDEF_DISCOVERED для этого конкретного действия.

person Michael Roland    schedule 17.01.2014
comment
Означает ли это, что с AAR нет решения? - person Manuel; 17.01.2014
comment
Вы имеете в виду только с AAR? Как правило, вы должны использовать AAR в качестве последней записи сообщения NDEF и использовать некоторые другие записи перед ним. Таким образом, с помощью вышеуказанного фильтра намерений вы будете запускать первую запись в этом сообщении (тот, который также содержит AAR в качестве последней записи). AAR по-прежнему гарантирует, что намерение, обнаруженное NDEF, будет передано только вашему приложению. Если вы действительно хотите, чтобы AAR был единственной записью в вашем сообщении, см. обновленный ответ (хотя обычно это не имеет особого смысла, поскольку в этом случае вы не будете передавать какие-либо данные). - person Michael Roland; 17.01.2014
comment
К вашему сведению: он работает с чистым AAR-решением. Большое спасибо, доктор Роланд! :) - person Manuel; 18.01.2014
comment
Я тоже сейчас пробовал делать AAR как дополнительную запись (после другой записи ndef). Но это не заставляет мое приложение запускаться автоматически (даже если указано в mainfest). TNF моей первой записи — Unknown (0x05) (потому что это просто двоичные данные). Является ли это проблемой (а может и причиной того, что не запускается)? - person Manuel; 14.02.2014
comment
Фильтры намерений работают только для первой записи в сообщении NDEF. Никогда не используйте TNF unknown для какой-либо записи (это означает не то, что полезная нагрузка записи представляет собой двоичные данные, а то, что сама запись по какой-либо причине не поддается анализу/интерпретации). Имя внешнего типа форума NFC (TNF=external + имя типа в соответствии со спецификацией RTD форума NFC). Затем вы можете настроить фильтр намерений на срабатывание для этого имени типа записи. - person Michael Roland; 14.02.2014
comment
Хорошо, приятно знать. Но если спросить об этом в целом: вы сказали, что AAR-запись может быть помещена в конец нескольких ndef-сообщений (даже без фильтра намерений), потому что Android всегда читает полный тег. Почему не работает в таком случае? - person Manuel; 14.02.2014
comment
Честно говоря, я не уверен. Я бы ожидал, что AAR все еще обрабатывается и что ваша дефолтная активность (та, которая фильтрует действие намерения MAIN) запущена. Если это не так, в стеке Android NFC может быть ошибка, из-за которой синтаксический анализ записи прерывается, когда записи помечены как неизвестные (форум AFAIK NFC требует, чтобы синтаксические анализаторы просто пропускали эти записи). Однако приведенный выше фильтр намерений (специально для AAR) всегда требует, чтобы AAR была первой записью. - person Michael Roland; 14.02.2014

Вам нужно использовать метод onNewIntent(), как описано в документации. Метод onCreate() должен содержать код установки, который у вас есть в onResume(). Это заставит приложение работать во всех случаях.

Из документации Android (http://developer.android.com/guide/topics/connectivity/nfc/advanced-nfc.html):

public void onPause() {
    super.onPause();
    mAdapter.disableForegroundDispatch(this);
}

public void onResume() {
    super.onResume();
    mAdapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray);
}

public void onNewIntent(Intent intent) {
    Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    //do something with tagFromIntent
}
person brwngrldev    schedule 16.01.2014
comment
-1 Подход к отправке на передний план из OP работает так же, как ваш подход. Вместо метода onNewIntent будет вызываться метод onActivityResult из-за использования ожидающего результата (createPendingResult). - person Michael Roland; 17.01.2014