2016-01-19 123 views
2

我是Android新手,致力於近場通信以讀取NFC標籤中的數據。我既沒有支持NFC的Android移動設備,也沒有NFC標籤來測試我創建的應用程序。通過僞造NFC標籤掃描來測試應用程序

我發現了下面兩篇關於通過觸發Intent來僞造NFC標籤掃描的帖子。

  1. Possibility for Fake NFC(Near Field Communication) Launch

  2. Need To Fake an NFC Tag Being Scanned In Android

我根據第一篇文章,其中一個按鈕的點擊,我引發了第一次活動所需的意圖改變了我的代碼。而我又創造了一個能夠處理同樣意圖的活動。 NFC標籤的閱讀和處理數據基於第二項活動中的按鈕點擊。

問題是:每當我從第一個活動觸發假NFC標籤掃描意圖時,它會拋出一個錯誤「找不到處理意圖的活動{act = android.nfc.action.NDEF_DISCOVERED(has extras) }「。

清單文件是這樣的:

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

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

<uses-feature android:name="android.hardware.nfc" android:required="false" /> 

<application 
    android:allowBackup="true" 
    android:icon="@mipmap/icon1" 
    android:label="@string/app_name" 
    android:supportsRtl="true" 
    android:theme="@style/AppTheme"> 
    <activity 
     android:name=".MainActivity" 
     android:label="@string/app_name" 
     android:theme="@style/AppTheme.NoActionBar"> 
     <intent-filter> 
      <action android:name="android.intent.action.MAIN" /> 

      <category android:name="android.intent.category.LAUNCHER" /> 
     </intent-filter> 
    </activity> 
    <activity 
     android:name=".Set_Monthly_Target" 
     android:label="@string/title_activity_set__monthly__target" 
     android:parentActivityName=".MainActivity"> 
     <meta-data 
      android:name="android.support.PARENT_ACTIVITY" 
      android:value="com.expensemanager.saubhattacharya.MainActivity" /> 
     <intent-filter> 
      <action android:name="android.nfc.action.NDEF_DISCOVERED" /> 
      <category android:name="android.intent.category.DEFAULT" /> 
      <data android:mimeType="text/plain"/> 
      <data android:mimeType="image/*" /> 
     </intent-filter> 
    </activity> 
    <activity 
     android:name=".Add_Daily_Expense" 
     android:label="@string/add_daily_expense_activity" 
     android:parentActivityName=".MainActivity"> 
     <meta-data 
      android:name="android.support.PARENT_ACTIVITY" 
      android:value="com.expensemanager.saubhattacharya.MainActivity" /> 
     <intent-filter> 
      <action android:name="android.nfc.action.NDEF_DISCOVERED" /> 
      <category android:name="android.intent.category.DEFAULT" /> 
      <data android:mimeType="text/plain"/> 
      <data android:mimeType="image/*" /> 
     </intent-filter> 
    </activity> 
</application> 

</manifest> 

從第一活性的意圖觸發代碼段低於:

public void scan_tag (View view) 
{ 
    final Intent intent = new Intent(NfcAdapter.ACTION_NDEF_DISCOVERED); 
    intent.putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, "Custom Messages"); 
    startActivity(intent); 
} 

從第二活動的代碼片段,它處理上述觸發如下:

public class Add_Daily_Expense extends AppCompatActivity { 

Button read_data; 
TextView show_data; 
Tag detected_tag; 
NfcAdapter nfcAdapter; 
IntentFilter[] intentFilters; 
public static final String MIME_TEXT_PLAIN = "text/plain"; 
public static final String MIME_IMAGE_ALL = "image/*"; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_add__daily__expense); 
    final PackageManager pm = this.getPackageManager(); 
    show_data = (TextView) findViewById(R.id.show_data); 
    nfcAdapter = NfcAdapter.getDefaultAdapter(getApplicationContext()); 
    read_data = (Button) findViewById(R.id.read_nfc); 
    read_data.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC)) { 
       try { 
        AlertDialog.Builder builder = new AlertDialog.Builder(Add_Daily_Expense.this); 
        builder.setMessage("NFC feature is not available on this device!") 
          .setCancelable(false) 
          .setPositiveButton("OK", new DialogInterface.OnClickListener() { 
           public void onClick(DialogInterface dialog, int id) { 
            dialog.cancel(); 
           } 
          }); 
        AlertDialog alert = builder.create(); 
        alert.show(); 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 
      } else { 
       Toast.makeText(getApplicationContext(), "NFC feature is available on this device!", Toast.LENGTH_SHORT).show(); 
       HandleIntent(getIntent()); 
      } 
     } 
    }); 
} 

public void HandleIntent(Intent intent) 
{ 
    String action = intent.getAction(); 
    if(NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) 
    { 
     detected_tag = getIntent().getParcelableExtra(nfcAdapter.EXTRA_TAG); 
     NDefReaderTask NDefReader = new NDefReaderTask(); 
     NDefReader.execute(); 
    } 
} 

public void onResume() 
{ 
    super.onResume(); 
    if(nfcAdapter != null) 
    setupForeGroundDispatch(this, nfcAdapter); 
} 

public void onPause() 
{ 
    super.onPause(); 
    if(nfcAdapter != null) 
    stopForeGroundDispatch(this, nfcAdapter); 
} 

public void onNewIntent(Intent intent) 
{ 
    HandleIntent(intent); 
} 

public void setupForeGroundDispatch (final Activity activity, NfcAdapter nfcAdapter) 
{ 
    Intent new_intent = new Intent(getApplicationContext(),Add_Daily_Expense.class); 
    new_intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); 

    PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(),0,new_intent,0); 
    intentFilters = new IntentFilter[1]; 
    String[][] techList = new String[][]{}; 

    intentFilters[0] = new IntentFilter(); 
    intentFilters[0].addAction(NfcAdapter.ACTION_NDEF_DISCOVERED); 
    intentFilters[0].addCategory(Intent.CATEGORY_DEFAULT); 
    try { 
     intentFilters[0].addDataType(MIME_TEXT_PLAIN); 
     intentFilters[0].addDataType(MIME_IMAGE_ALL); 
    } 
    catch(IntentFilter.MalformedMimeTypeException me) 
    { 
     me.printStackTrace(); 
    } 

    nfcAdapter.enableForegroundDispatch(activity, pendingIntent, intentFilters, techList); 
} 

public void stopForeGroundDispatch (final Activity activity, NfcAdapter nfcAdapter) 
{ 
    nfcAdapter.disableForegroundDispatch(activity); 
} 

public class NDefReaderTask extends AsyncTask <Tag, Void, String> 
{ 
    @Override 
    protected String doInBackground(Tag... params) 
    { 
     try 
     { 
      detected_tag = params[0]; 
      Ndef ndef = Ndef.get(detected_tag); 
      ndef.connect(); 
      if(ndef != null) 
      { 
       NdefMessage ndefMessage = ndef.getCachedNdefMessage(); 
       NdefRecord[] records = ndefMessage.getRecords(); 
       for(NdefRecord ndefRecord : records) 
       { 
        if((ndefRecord.getTnf() == NdefRecord.TNF_ABSOLUTE_URI) || (ndefRecord.getTnf() == NdefRecord.TNF_WELL_KNOWN)) 
        { 
         byte[] payload = ndefRecord.getPayload(); 
         String encoding1 = "UTF-8"; 
         String encoding2 = "UTF-16"; 
         String textEncoding = ((payload[0] & 128) == 0) ? encoding1 : encoding2; 
         int languageCodeLength = payload[0] & 0063; 
         return new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncoding); 
        } 
       } 
      } 
      ndef.close(); 
     } 
     catch (UnsupportedEncodingException UE) 
     { 
      UE.printStackTrace(); 
     } 
     catch (IOException IE) 
     { 
      IE.printStackTrace(); 
     } 
     return null; 
    } 

    @Override 
    protected void onPreExecute() 
    { 

    } 

    protected void onPostExecute(String result) 
    { 
     if(result != null) 
     { 
      show_data.setText(result); 
     } 
    } 
} 
} 

我的問題是:我在這裏做什麼錯?有沒有其他方法通過僞造NFC標籤掃描來測試我的應用程序?

回答

2

您指定NDEF_DISCOVERED意圖過濾MIME類型的過濾器:

<data android:mimeType="text/plain"/> 
<data android:mimeType="image/*" /> 

因此,假NFC意圖需要包含這些MIME類型相匹配的意圖過濾器之一。您可以使用setType()方法的類型信息添加到意圖:

public void scan_tag (View view) { 
    final Intent intent = new Intent(NfcAdapter.ACTION_NDEF_DISCOVERED); 
    intent.setType("text/plain"); 
    intent.putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, ...); 
    startActivity(intent); 
} 

還要注意的是,上面的代碼不會在標籤手柄增加了NFC的意圖。因此,你不能獲得與

detected_tag = getIntent().getParcelableExtra(nfcAdapter.EXTRA_TAG); 

一個Tag對象。因此,你也可以不使用

Ndef ndef = Ndef.get(detected_tag); 

你可能要考慮以下幾個問題得到Ndef連接類的一個實例關於模擬標籤的對象/回答:

最後,要知道,有在你的代碼等幾個問題。

+0

@ Michael--非常感謝!我將通讀你提到的幾點,並讓你知道結果。是的,我認爲我的代碼中會有幾個,因爲我是新手,所以我想做適當的單元測試。 :) –

+0

@ Michael--如果可能的話,你能不能告訴我大概在我的代碼中有哪些所有問題?或者我在這種情況下的做法是錯誤的?我正在嘗試做一些單元測試。 –

+0

我能夠通過僅將MIME類型保留爲文本來解決此問題。我能夠捕捉到意圖。但由於我無法獲得NFC適配器和標籤信息,因此我無法測試整個代碼。 同時,如果可能的話,請突出顯示代碼中的所有問題? –