Сообщение Android NDEF с двумя действиями и неверным содержанием намерений

Я новичок в NFC с Android и пытаюсь создать приложение для обмена сообщениями с NFC.

У меня есть первое действие, которое отправляет содержимое представления EditText на другой телефон при передаче и отображает входящее сообщение в TextView на другом телефоне. Это прекрасно работает.

У меня есть другое действие, которое используется для добавления контакта в реестр контактов, оно должно работать следующим образом:

  • A хочет добавить B в качестве контакта,
  • А переходит к AddContactActivity, вводит имя контакта в представлении EditText,
  • затем B касается телефона A (в том же действии) и отправляет свой идентификатор (открытый ключ для дальнейшего шифрования).

Моя проблема заключается в том, что хотя код, касающийся отправки через NFC, в основном одинаков для двух действий, когда я передаю вторую активность (AddContactActivity), действие отправленного намерения — ACTION_MAIN вместо ACTION_NDEF_DISCOVERED, что имеет эффект открытие первого занятия и, таким образом, не прохождение правильного лечения.

Вот код MainActivity:

public class MainActivity extends Activity {

    private TextView mTextView;
    private EditText mEdit;

    NfcAdapter nfcAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = getIntent();

        mTextView = (TextView)findViewById(R.id.retour);
        mEdit = (EditText)findViewById(R.id.editText);

        nfcAdapter = NfcAdapter.getDefaultAdapter(getApplicationContext());

        nfcAdapter.setNdefPushMessageCallback(new NfcAdapter.CreateNdefMessageCallback() {
            @Override public NdefMessage createNdefMessage(NfcEvent event) {

                String stringOut = mEdit.getText().toString();

                byte[] bytesOut = stringOut.getBytes();

                NdefRecord ndefRecordOut = new NdefRecord(
                        NdefRecord.TNF_MIME_MEDIA,
                        "text/plain".getBytes(),
                        new byte[] {},
                        bytesOut);

                NdefMessage ndefMessageout = new NdefMessage(ndefRecordOut);

                return ndefMessageout;
            }
        }, this);

        checkAndProcessBeamIntent(intent);

    }

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

        Intent intent = getIntent();

        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
        IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);

        try {
            ndef.addDataType("text/plain");
        } catch (IntentFilter.MalformedMimeTypeException e) {
            e.printStackTrace();
        }

        IntentFilter[] intentFiltersArray = new IntentFilter[] {ndef, };
        nfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, null);
    }


    private void checkAndProcessBeamIntent(Intent intent) {
        String action = intent.getAction();

        if(action.equals(NfcAdapter.ACTION_NDEF_DISCOVERED)){
            Parcelable[] parcelables =
                    intent.getParcelableArrayExtra(
                            NfcAdapter.EXTRA_NDEF_MESSAGES);

            NdefMessage inNdefMessage = (NdefMessage)parcelables[0];
            NdefRecord[] inNdefRecords = inNdefMessage.getRecords();
            NdefRecord NdefRecord_0 = inNdefRecords[0];

            String inMsg = new String(NdefRecord_0.getPayload());

            mTextView.setText(inMsg);

        }
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Toast.makeText(MainActivity.this,
                intent.getAction().toString(),
                Toast.LENGTH_LONG).show();
        checkAndProcessBeamIntent(intent);
    }

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


    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
    public void generateKeys(){
        Calendar cal = Calendar.getInstance();
        Date now = cal.getTime();
        cal.add(Calendar.YEAR, 1);
        Date end = cal.getTime();

        KeyPairGenerator kpg = null;
        try {
            kpg = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchProviderException e) {
            e.printStackTrace();
        }
        try {
            kpg.initialize(new KeyPairGeneratorSpec.Builder(getApplicationContext())
                    .setAlias("Keys")
                    .setStartDate(now)
                    .setEndDate(end)
                    .setSerialNumber(BigInteger.valueOf(1))
                    .setSubject(new X500Principal("CN=test1"))
                    .build());
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }

        kpg.generateKeyPair();
    }

    public void goToAddContact(View view) {
        Intent intent = new Intent(this, AddContactActivity.class);
        intent.setAction("NewActivity");
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        startActivity(intent);

    }
}

Вот код AddContactActivity:

public class AddContactActivity extends Activity{

    NfcAdapter nfcAdapter;
    EditText editText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_contact);

        editText = (EditText)findViewById(R.id.editText);

        nfcAdapter = NfcAdapter.getDefaultAdapter(getApplicationContext());

        Intent intent = getIntent();

        nfcAdapter.setNdefPushMessageCallback(new NfcAdapter.CreateNdefMessageCallback() {
            @Override public NdefMessage createNdefMessage(NfcEvent event) {

                String stringOut = getMyPublicKey();

                byte[] bytesOut = stringOut.getBytes();

                NdefRecord ndefRecordOut = new NdefRecord(
                        NdefRecord.TNF_MIME_MEDIA,
                        "text/plain".getBytes(),
                        new byte[] {},
                        bytesOut);

                NdefMessage ndefMessageout = new NdefMessage(ndefRecordOut);

                return ndefMessageout;
            }
        }, this);

        checkAndProcessBeamIntent(intent);

    }

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

        Intent intent = getIntent();

        Toast.makeText(AddContactActivity.this,
                "onResume : "+intent.getAction().toString(),
                Toast.LENGTH_LONG).show();

        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
        IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);

        try {
            ndef.addDataType("text/plain");
        } catch (IntentFilter.MalformedMimeTypeException e) {
            e.printStackTrace();
        }

        IntentFilter[] intentFiltersArray = new IntentFilter[] {ndef, };
        nfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, null);
    }

    public void addContactDataBase(String publicKey){

        SQLiteHelper sqLiteHelper = new SQLiteHelper(this);
        sqLiteHelper.addUser(new User(editText.getText().toString(), publicKey));
    }

    public void checkUserInDataBase(String publicKey){
        SQLiteHelper sqLiteHelper = new SQLiteHelper(this);
        User u = sqLiteHelper.getUser(publicKey);
        Toast.makeText(AddContactActivity.this,
                ""+u.getName(),
                Toast.LENGTH_LONG).show();
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Toast.makeText(AddContactActivity.this,
                "OnNewIntent : "+intent.getAction().toString(),
                Toast.LENGTH_LONG).show();
        checkAndProcessBeamIntent(intent);
    }

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

    private void checkAndProcessBeamIntent(Intent intent) {
        String action = intent.getAction();

        if(action.equals(NfcAdapter.ACTION_NDEF_DISCOVERED)){
            Toast.makeText(AddContactActivity.this,
                    "COUCOU",
                    Toast.LENGTH_LONG).show();
            Parcelable[] parcelables =
                    intent.getParcelableArrayExtra(
                            NfcAdapter.EXTRA_NDEF_MESSAGES);

            NdefMessage inNdefMessage = (NdefMessage)parcelables[0];
            NdefRecord[] inNdefRecords = inNdefMessage.getRecords();
            NdefRecord NdefRecord_0 = inNdefRecords[0];

            String inMsg = new String(NdefRecord_0.getPayload());

            addContactDataBase(inMsg);
            checkUserInDataBase(inMsg);

        }
    }

    public String getMyPublicKey(){
        KeyStore ks = null;
        RSAPublicKey publicKey = null;
        try {
            ks = KeyStore.getInstance("AndroidKeyStore");
            ks.load(null);


            KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry)ks.getEntry("Keys", null);
            publicKey = (RSAPublicKey) keyEntry.getCertificate().getPublicKey();

        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (UnrecoverableEntryException e) {
            e.printStackTrace();
        }
        return publicKey.toString();
    }
}

А вот и манифест:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.bsauzet.testnfc" >

    <uses-permission android:name="android.permission.NFC" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.nfc.action.NDEF_DISCOVERED" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="text/plain" />
            </intent-filter>

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

        </activity>
        <activity
            android:name=".AddContactActivity"
            android:label="@string/title_activity_add_contact"
            android:launchMode="singleTop">

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

        </activity>
    </application>

</manifest>

person Awanegenebayo    schedule 02.06.2015    source источник


Ответы (2)


Проверьте свои библиотеки appCompat. Повреждение библиотек appCompat может привести к неправильным исключениям намерений. Особенно, когда вы перемещаете свой проект с другого ПК или рабочего пространства (и/или IDE).

person metzelder    schedule 02.06.2015
comment
Привет, спасибо за вашу помощь. Мои библиотеки appcompat не повреждены, однако я не уверен, как это проверить ^^' - person Awanegenebayo; 03.06.2015
comment
Вы можете попробовать переустановить в своем пути сборки Java. - person metzelder; 03.06.2015

Получение намерения с ACTION_MAIN вместо ACTION_NDEF_DISCOVERED при получении события NFC является типичным признаком того, что сообщение NDEF, содержащее запись приложения Android (AAR), было получено и что тип данных первой записи сообщения NDEF не соответствует ни одному фильтру намерений. .

Ваш метод CreateNdefMessageCallback.createNdefMessage() явно не добавляет AAR к сообщению NDEF. Следовательно, единственная причина, по которой вы по-прежнему будете получать сообщение NDEF, содержащее AAR, заключается в том, что createNdefMessage() вызывает необработанное исключение. В этом случае стек NFC автоматически сгенерирует сообщение NDEF, содержащее ссылку на Play Store и AAR.

Наиболее вероятным местом, где createNdefmessage() может вызвать необработанное исключение, является getMyPublicKey() (поскольку это единственная часть, которая отличается между MainActivity и AddContactActivity).

Таким образом, мы можем отследить проблему до этой части вашего кода:

ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry)ks.getEntry("Keys", null);
publicKey = (RSAPublicKey) keyEntry.getCertificate().getPublicKey();

Этот код либо

  • вызывает необработанное исключение времени выполнения (например, если ks, keyEntry или keyEntry.getCertificate() равно null или если ks.getEntry("Keys", null) нельзя преобразовать в KeyStore.PrivateKeyEntry), или
  • вызывает любое из обрабатываемых исключений, из-за чего publicKey становится null, что приводит к необработанному NullPointerException при попытке вызвать toString()return publicKey.toString();).
person Michael Roland    schedule 10.06.2015