Download presentation
Presentation is loading. Please wait.
1
第15章 網路與通訊 15-1 WebView元件-行動瀏覽器 15-2 簡訊處理-我的簡訊 15-3 寄送電子郵件-郵件寄送工具
15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 15-5 簡訊與定位服務-GPS間諜簡訊
2
15-1 WebView元件-行動瀏覽器 在Android應用程式可以使用WebView元件來瀏覽網頁內容,換句話說,我們可以使用WebView元件建立自己的瀏覽器。
3
15-1 WebView元件-行動瀏覽器 步驟一:開啟和執行Android Studio專案
請啟動Android Studio開啟專案Ch15_1,內含1個Java類別檔和版面配置檔activity_main.xml,其執行結果如右圖所示:
4
15-1 WebView元件-行動瀏覽器 步驟二:建立WebView元件的版面配置
行動瀏覽器的使用介面是定義在activity_main.xml版面配置檔,在刪除TextView元件後,水平編排1個EditText(txtUrl)和Button(button,onClick屬性值是button_Click)元件,如下圖所示:
5
15-1 WebView元件-行動瀏覽器 步驟三:建立Activity活動類別
在MainActivity活動類別的開頭宣告成員變數ProgressBar、WebView和EditText物件,如下所示: public class MainActivity extends ActionBarActivity { private ProgressBar progressbar; private WebView web; private EditText txtUrl; …... }
6
15-1 WebView元件-行動瀏覽器 步驟三:建立Activity活動類別-onCreate()方法
在覆寫onCreate()方法載入版面配置後,依序取得ProgressBar、WebView和EditText物件,如下所示: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); progressbar = (ProgressBar) findViewById(R.id.progressBar); web = (WebView) findViewById(R.id.webView); initWebBrowser(); txtUrl = (EditText) findViewById(R.id.txtUrl); String strUrl = txtUrl.getText().toString(); loadUrl(web, strUrl); }
7
15-1 WebView元件-行動瀏覽器 步驟三:建立Activity活動類別-initWebBrowser()方法
在initWebBrowser()方法初始WebView物件和顯示載入網頁的進度對話方塊,如下所示: public void initWebBrowser() { // 初始WebView元件 web.getSettings().setJavaScriptEnabled(true); web.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY); web.setWebViewClient(new WebViewClient(){ public boolean shouldOverrideUrlLoading( final WebView view, final String url) { loadUrl(view, url); return true; } });
8
15-1 WebView元件-行動瀏覽器 步驟三:建立Activity活動類別-setWebChromeClient()方法
WebView物件的setWebChromeClient()方法指定使用的WebChromeClient客戶端物件,如下所示: web.setWebChromeClient(new WebChromeClient(){ public void onProgressChanged(WebView view,int progress) { progressbar.setProgress(progress); super.onProgressChanged(view, progress); } });
9
15-1 WebView元件-行動瀏覽器 步驟三:建立Activity活動類別-loadUrl()方法
自訂方法loadUrl()可以在WebView元件載入網頁,如下所示: public void loadUrl(final WebView view,final String url){ progressbar.setProgress(0); view.loadUrl(url); }
10
15-1 WebView元件-行動瀏覽器 步驟三:建立Activity活動類別-button_Click()方法
Button元件的事件處理方法是當使用者在EditText元件輸入新網址後,按下按鈕,就呼叫此方法來載入URL網址的網頁,如下所示: public void button_Click(View view) { String strUrl = txtUrl.getText().toString(); loadUrl(web, strUrl); }
11
15-1 WebView元件-行動瀏覽器 步驟三:建立Activity活動類別-onKeyDown()方法
在onKeyDown()方法是處理使用者按下返回鍵(BACK)回到上一頁網頁,如果沒有上一頁網頁,就顯示對話方塊,確認是否離開行動瀏覽器,如下所示: @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if ((keyCode == KeyEvent.KEYCODE_BACK) && web.canGoBack()) { web.goBack(); return true; } else if(keyCode == KeyEvent.KEYCODE_BACK) {
12
15-1 WebView元件-行動瀏覽器 步驟三:建立Activity活動類別-onKeyDown()方法
AlertDialog.Builder aDlg = new AlertDialog.Builder(this); aDlg.setTitle("離開行動瀏覽器") .setMessage("請確認離開行動瀏覽器?") .setPositiveButton("是", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int i) { MainActivity.this.finish(); } }) .setNegativeButton("否", null).show(); return true; return super.onKeyDown(keyCode, event);
13
15-1 WebView元件-行動瀏覽器 步驟四:在AndroidManifest.xml新增存取Internet權限
行動瀏覽器因為需要連線Internet,所以在AndroidManifest.xml檔新增INTERNET權限,如下所示: <uses-permission android:name="android.permission.INTERNET"/>
14
15-2 簡訊處理-我的簡訊 行動裝置的主要功能就是對外通訊,我們除了使用語音通話外,另一個常用功能是「簡訊」(Short Message Service,SMS),即手機的文字訊息服務。 在這一節筆者準備說明如何在Android應用程式收發簡訊,我們需要使用廣播接收器來取得與顯示簡訊的內容。
15
15-2 簡訊處理-我的簡訊 步驟一:開啟和執行Android Studio專案
請啟動Android Studio開啟專案Ch15_2,內含2個Java類別檔和1個版面配置檔activity_main.xml,因為需要測試簡訊傳送,我們需要同時啟動2個Android模擬器,以筆者為例是GPhone和MyPhone,在視窗標題文字的「:」符號前是電話號碼,以此例分別為5554和5556。 請在GPhone模擬器執行Android專案Ch15_2,其執行結果如右圖所示:
16
15-2 簡訊處理-我的簡訊 步驟二:建立寄送簡訊使用介面的版面配置
寄送簡訊的使用介面是定義在activity_main.xml版面配置檔,依序垂直編排2個TextView和EditText(txtPhoneNo、txtMessage)元件,一個Button元件,如下圖所示:
17
15-2 簡訊處理-我的簡訊 步驟三:建立Activity活動類別寄送簡訊
在MainActivity活動類別的開頭宣告成員變數EditText物件txtPhoneNo和txtMessage,如下所示: public class MainActivity extends ActionBarActivity { private EditText txtPhoneNo, txtMessage; … }
18
15-2 簡訊處理-我的簡訊 步驟三:建立Activity活動類別寄送簡訊-onCreate()
在覆寫的onCreate()方法載入版面配置後,可以取得2個EditText物件,如下所示: @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); txtPhoneNo = (EditText) findViewById(R.id.txtPhoneNo); txtMessage = (EditText) findViewById(R.id.txtMessage); }
19
15-2 簡訊處理-我的簡訊 步驟三:建立Activity活動類別寄送簡訊-button_Click()
public void button_Click(View view) { String phoneNo = txtPhoneNo.getText().toString(); String message = txtMessage.getText().toString(); if (phoneNo.length() > 0 && message.length() > 0) sendSMS(phoneNo, message); else Toast.makeText(this, "請確認輸入電話號碼和訊息內容!", Toast.LENGTH_SHORT).show(); }
20
15-2 簡訊處理-我的簡訊 步驟三:建立Activity活動類別寄送簡訊-sendSMS()
private void sendSMS(String phoneNumber, String message) { String SENT = "SMS_SENT"; String DELIVERED = "SMS_DELIVERED"; registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context content, Intent intent) { switch (getResultCode()) { case Activity.RESULT_OK: Toast.makeText(getBaseContext(), "簡訊送出", Toast.LENGTH_SHORT).show(); break; case SmsManager.RESULT_ERROR_GENERIC_FAILURE: Toast.makeText(getBaseContext(), "一般錯誤!",
21
15-2 簡訊處理-我的簡訊 步驟三:建立Activity活動類別寄送簡訊-sendSMS()
case SmsManager.RESULT_ERROR_NO_SERVICE: Toast.makeText(getBaseContext(), "沒有服務!", Toast.LENGTH_SHORT).show(); break; case SmsManager.RESULT_ERROR_NULL_PDU: Toast.makeText(getBaseContext(), "空的PDU", case SmsManager.RESULT_ERROR_RADIO_OFF: Toast.makeText(getBaseContext(), "沒有訊號", } }, new IntentFilter(SENT));
22
15-2 簡訊處理-我的簡訊 步驟三:建立Activity活動類別寄送簡訊-sendSMS()
當簡訊送達,我們再建立一個廣播接收器取得是否送達的結果,如下所示: registerReceiver(new BroadcastReceiver() { public void onReceive(Context content, Intent intent) { switch (getResultCode()) { case Activity.RESULT_OK: Toast.makeText(getBaseContext(), "簡訊已經送達!", Toast.LENGTH_SHORT).show(); break; case Activity.RESULT_CANCELED: Toast.makeText(getBaseContext(), "簡訊沒有送達!", } }, new IntentFilter(DELIVERED));
23
15-2 簡訊處理-我的簡訊 步驟三:建立Activity活動類別寄送簡訊-sendSMS()
寄送簡訊首先是建立PendingIntent物件,如下所示: PendingIntent sentPI = PendingIntent.getBroadcast( this, 0, new Intent(SENT), 0); PendingIntent deliveredPI = PendingIntent.getBroadcast( this, 0, new Intent(DELIVERED), 0); 上述PendingIntent物件包裝的Intent物件分別送出SMS_SENT和SMS_DELIVERED廣播。
24
15-2 簡訊處理-我的簡訊 步驟三:建立Activity活動類別寄送簡訊-sendSMS()
然後取得SmsManager物件寄送簡訊,使用SmsManager類別的getDefault()方法來取得此物件,如下所示: SmsManager sms = SmsManager.getDefault(); sms.sendTextMessage(phoneNumber, null, message, sentPI, deliveredPI); }
25
15-2 簡訊處理-我的簡訊 步驟四:建立BroadcastReceiver類別接收簡訊-1
在Android應用程式可以使用廣播接收器接收行動裝置收到簡訊的系統廣播,換句話說,我們可以透過它來過濾出我們需要的簡訊,在第15-5節就是使用此方法來找出間諜簡訊。 Android Studio專案Ch15_2建立SMSReceiver.java類別檔的廣播接收器,如下所示: public class SMSReceiver extends BroadcastReceiver { … }
26
15-2 簡訊處理-我的簡訊 步驟四:建立BroadcastReceiver類別接收簡訊-2
我們需要覆寫onReceive()方法來建立廣播接收器,如下所示: @Override public void onReceive(Context context, Intent intent) { Bundle bundle = intent.getExtras(); SmsMessage[] msgs = null; String str = ""; 如果有,就取出簡訊中的電話號碼和內容,簡訊內容是儲存在PDU格式的Object[]陣列,如下所示: if (bundle != null) { Object[] pdus = (Object[]) bundle.get("pdus"); msgs = new SmsMessage[pdus.length];
27
15-2 簡訊處理-我的簡訊 步驟四:建立BroadcastReceiver類別接收簡訊-3
for (int i = 0; i < msgs.length; i++){ msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]); str += "SMS from " + msgs[i].getOriginatingAddress(); str += " :"; str += msgs[i].getMessageBody().toString(); str += "\n"; } Toast.makeText(context, str, Toast.LENGTH_LONG).show();
28
15-2 簡訊處理-我的簡訊 步驟五:在AndroidManifest.xml註冊廣播接收器和新增權限1
SMSReceiver廣播接收器需要在AndroidManifest.xml檔註冊,Telephony.SMS_RECEIVED是處理行動裝置收到簡訊的系統廣播,如下所示: <receiver android:name=".SMSReceiver"> <intent-filter> <action android:name= "android.provider.Telephony.SMS_RECEIVED" /> </intent-filter> </receiver>
29
15-2 簡訊處理-我的簡訊 步驟五:在AndroidManifest.xml註冊廣播接收器和新增權限2
<uses-permission android:name="android.permission.SEND_SMS" /> <uses-permission android:name="android.permission.RECEIVE_SMS" />
30
15-3 寄送電子郵件-郵件寄送工具 如同簡訊,我們也可以建立Android應用程式來寄送電子郵件,不過,我們並不是直接寄送,而是透過Intent物件呼叫內建郵件工具來寄送電子郵件。
31
15-3 寄送電子郵件-郵件寄送工具 步驟一:開啟和執行Android Studio專案
請啟動Android Studio開啟專案Ch15_3,內含1個Java類別檔和版面配置檔activity_main.xml,其執行結果如下圖所示:
32
15-3 寄送電子郵件-郵件寄送工具 步驟二:建立郵件寄送工具使用介面的版面配置
寄送郵件的使用介面是定義在activity_main.xml版面配置檔,依序垂直編排2個TextView和EditText(txtAddress、txtBody)元件,一個Button元件,如下圖所示:
33
15-3 寄送電子郵件-郵件寄送工具 步驟三:建立Activity活動類別寄送電子郵件
在MainActivity活動類別的開頭宣告成員變數Button和EditText物件變數,如下所示: public class MainActivity extends ActionBarActivity { Button send; EditText address, body; … }
34
15-3 寄送電子郵件-郵件寄送工具 步驟三:建立Activity活動類別寄送電子郵件-onCreate()
在覆寫onCreate()方法載入版面配置後,取得2個EditText物件的郵件內容,如下所示: @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); address = (EditText) findViewById(R.id.txtAddress); body = (EditText) findViewById(R.id.txtBody); }
35
15-3 寄送電子郵件-郵件寄送工具 步驟三:建立Activity活動類別寄送電子郵件-button_Click()
在Button元件的事件處理方法啟動內建郵件工具來寄送電子郵件,首先使用if條件檢查是否有輸入電子郵件地址,然後建立Intent物件,如下所示: public void button_Click(View view) { if (!address.getText().toString().trim().equalsIgnoreCase("")) { Intent eIntent = new Intent( android.content.Intent.ACTION_SEND); eIntent.setType("plain/text"); eIntent.putExtra(Intent.EXTRA_ , new String[]{ address.getText().toString()}); eIntent.putExtra(Intent.EXTRA_TEXT, body.getText()); startActivity(Intent.createChooser(eIntent, "寄送電子郵件...")); } else { Toast.makeText(this, "請輸入電子郵件地址..", Toast.LENGTH_LONG).show();
36
15-4 檔案下載與AsyncTask抽象類別- 大型檔案下載
在Android應用程式下載檔案建議使用執行緒,我們可以直接繼承AsyncTask抽象類別來建立執行緒,此類別可以建立執行緒來執行背景作業,換句話說,我們可以直接繼承AsyncTask抽象類別來執行大型檔案的下載。
37
15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟一:開啟和執行Android Studio專案
請啟動Android Studio開啟專案Ch15_4,內含2個Java類別檔和版面配置檔activity_main.xml,其執行結果如下圖所示:
38
15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟二:建立大型檔案下載使用介面的版面配置
大型檔案下載的使用介面是定義在activity_main.xml版面配置檔,依序編排2個TextView和EditText元件,最後是Button元件,如下圖所示:
39
15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟三:DialogFragment執行進度對話方塊-1
DialogFragment執行進度對話方塊是修改第8-3-3節範例,ProgressDialogFragment類別繼承DialogFragment類別,和宣告成員變數pDialog,如下所示: public class ProgressDialogFragment extends DialogFragment { private ProgressDialog pDialog; ….... }
40
在newInstance()類別方法建立ProgressDialogFragment物件後,指定附加的標題文字參數,如下所示:
15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟三:DialogFragment執行進度對話方塊-newInstance() 在newInstance()類別方法建立ProgressDialogFragment物件後,指定附加的標題文字參數,如下所示: static ProgressDialogFragment newInstance(String title) { ProgressDialogFragment dlg = new ProgressDialogFragment(); Bundle args = new Bundle(); args.putString("title", title); dlg.setArguments(args); return dlg; }
41
15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟三:DialogFragment執行進度對話方塊-onCreateDialog()
在覆寫onCreateDialog()方法取得標題文字參數title後,建立ProgressDialog進度對話方塊物件,如下所示: @Override public Dialog onCreateDialog(Bundle savedInstanceState) { String title = getArguments().getString("title"); pDialog = new ProgressDialog(getActivity()); pDialog.setTitle(title); pDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); pDialog.setProgress(0); return pDialog; }
42
在updateProgress()方法呼叫setProgress()方法來更新目前進度,如下所示:
15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟三:DialogFragment執行進度對話方塊-updateProgress() 在updateProgress()方法呼叫setProgress()方法來更新目前進度,如下所示: public void updateProgress(Integer progress) { pDialog.setProgress(progress); }
43
15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟四:在Activity類別使用AsyncTask類別下載檔案
在MainActivity活動類別開頭宣告成員變數ProgressDialogFragment物件變數,和檔案名稱字串,如下所示: public class MainActivity extends ActionBarActivity { private ProgressDialogFragment dlg; private String filename; ….... }
44
在覆寫onCreate()方法載入版面配置後,取得Button物件和建立Click事件處理方法,如下所示:
15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟四:在Activity類別使用AsyncTask類別下載檔案-onCreate() 在覆寫onCreate()方法載入版面配置後,取得Button物件和建立Click事件處理方法,如下所示: @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btn = (Button)findViewById(R.id.button); 上述程式碼取得Button元件btn後,指定傾聽者物件的事件處理方法,這是使用匿名內層類別建立的傾聽者物件。
45
實作介面的onClick()方法,如下所示:
15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟四:在Activity類別使用AsyncTask類別下載檔案-onCreate() 實作介面的onClick()方法,如下所示: btn.setOnClickListener(new View.OnClickListener(){ public void onClick(View v) { EditText txtUrl = (EditText) findViewById(R.id.txtUrl); String url = txtUrl.getText().toString(); EditText txtFile = (EditText) findViewById(R.id.txtFile); filename = txtFile.getText().toString(); new AsyncDownloadLargeFile(filename).execute(url); } });
46
15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟四:在Activity類別使用AsyncTask類別下載檔案-抽象類別1
class AsyncDownloadLargeFile extends AsyncTask<String, Integer, String> { private String file; public AsyncDownloadLargeFile(String filename) { file = filename; } ……
47
15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟四:在Activity類別使用AsyncTask類別下載檔案-抽象類別2
Step 1:首先呼叫onPreExecute()方法建立和啟動執行緒,通常我們會在此方法設定作業和顯示進度對話方塊,如下所示: @Override protected void onPreExecute() { super.onPreExecute(); dlg = ProgressDialogFragment.newInstance("下載檔案..."); FragmentManager fm = getSupportFragmentManager(); dlg.show(fm, "progressdialog"); }
48
15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟四:在Activity類別使用AsyncTask類別下載檔案-抽象類別3
Step 2:doInBackground(Params...)方法是在onPreExecute()方法之後執行,我們可以在此方法執行長時間的背景作業,例如:下載大型檔案,執行期間可以呼叫publishProgress(Progress...)方法送出目前進度,然後在Step 3的onProgressUpdate()方法更新。doInBackground()方法參數String後的省略符號「...」,表示參數是可變長度的參數列,第1個參數是urls[0](詳見第A-4-4節的說明),如下所示: @Override protected String doInBackground(String... urls) { int count; try { URL url = new URL(urls[0]); URLConnection con = url.openConnection(); con.connect(); int len = con.getContentLength(); Log.d("Ch15_4", "檔案尺寸: " + len); InputStream in = new BufferedInputStream(url.openStream()); OutputStream out = new FileOutputStream("/sdcard/" + file);
49
15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟四:在Activity類別使用AsyncTask類別下載檔案-抽象類別4
下方程式碼是使用while迴圈讀取遠端檔案和寫入下載檔案至SD卡,publishProgress()方法更新下載檔案的進度,如下所示: byte data[] = new byte[1024]; long total = 0; while ((count = in.read(data)) != -1) { total += count; publishProgress((int)((total*100)/len)); out.write(data, 0, count); } out.flush(); out.close(); in.close(); } catch (Exception e) {} return null;
50
15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟四:在Activity類別使用AsyncTask類別下載檔案-抽象類別5
Step 3:當在Step 2呼叫publishProgress()方法後,就會呼叫onProgressUpdate(Progress...)方法,我們可以在此方法更新進度,例如:更新進度對話方塊顯示的進度,即呼叫updateProgress()方法,Integer後的省略符號「...」表示參數是可變長度的參數列,第1個參數是progress[0] (詳見第A-4-4節的說明),如下所示: @Override protected void onProgressUpdate(Integer... progress) { Log.d("Ch15_4", "進度: " + progress[0]); dlg.updateProgress(progress[0]); }
51
15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟四:在Activity類別使用AsyncTask類別下載檔案-抽象類別6
Step 4:onPostExecute(Result)是在背景操作執行完畢後呼叫,我們可以在此步驟隱藏進度對話方塊,其方法參數並沒有使用,如下所示: @Override protected void onPostExecute(String unused) { dlg.dismiss(); }
52
15-4 檔案下載與AsyncTask抽象類別-大型檔案下載 步驟五:在AndroidManifest.xml新增權限
大型檔案下載因為需要連線Internet和在外部儲存裝置寫入檔案,所以在AndroidManifest.xml檔需要新增INTERNET和WRITE_EXTERNAL_STORAGE權限,如下所示: <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name= "android.permission.WRITE_EXTERNAL_STORAGE"/>
53
15-5 簡訊與定位服務-GPS間諜簡訊 GPS間諜簡訊是簡訊與定位服務的應用,當執行此程式,只需接到特定暗號的簡訊,行動裝置就會自動送出簡訊告知目前行動裝置的經緯度座標,換句話說,我們可以發送簡訊來得知遺失手機的位置,或使用簡訊來查詢或追蹤小孩或老人家目前的位置。
54
15-5 簡訊與定位服務-GPS間諜簡訊 步驟一:開啟和執行Android Studio專案
請啟動Android Studio開啟專案Ch15_5,內含2個Java類別檔和版面配置檔activity_main.xml。首先啟動Android Device Monitor,在左邊選準備執行程式的GPhone模擬器;右邊選【Emulator Control】標籤找到輸入經緯度座標的欄位,如下圖所示:
55
15-5 簡訊與定位服務-GPS間諜簡訊 步驟二:建立GPS間諜簡訊使用介面的版面配置
GPS間諜簡訊的使用介面是定義在activity_main.xml版面配置檔,依序編排1個TextView和EditText元件來輸入暗號,最後是Button元件(onClick屬性值是button_Click),如下圖所示:
56
15-5 簡訊與定位服務-GPS間諜簡訊 步驟三:建立Activity活動輸入和儲存暗號-1
在MainActivity活動類別的開頭宣告public的3個常數,和2個成員變數SharedPreferences和EditText物件變數,如下所示: public class MainActivity extends ActionBarActivity { public static final String PREFERENCES = "SPYSMSPreferences"; public static final String PREFERENCES_CODE = "SPYSMSPreferenceCode"; public static final String PREFERENCES_CODE_DEFAULT = "SPY"; private EditText txtCode; private SharedPreferences prefs; …... }
57
15-5 簡訊與定位服務-GPS間諜簡訊 步驟三:建立Activity活動輸入和儲存暗號- onCreate()
在覆寫onCreate()方法載入版面配置後,取得EditText元件和SharedPreferences物件,如下所示: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); txtCode = (EditText) findViewById(R.id.txtCode); prefs = getSharedPreferences(PREFERENCES, MODE_PRIVATE); }
58
15-5 簡訊與定位服務-GPS間諜簡訊 步驟三:建立Activity活動輸入和儲存暗號- button_Click()
在Button元件的事件處理方法是以使用者偏好設定檔來儲存暗號,在取得SharedPreferences.Editor物件後,呼叫putString()和apply()方法寫入暗號字串至檔案,如下所示: public void button_Click(View view) { SharedPreferences.Editor prefEdit = prefs.edit(); prefEdit.putString(PREFERENCES_CODE, txtCode.getText().toString()); prefEdit.apply(); Toast.makeText(this, "成功儲存暗號!", Toast.LENGTH_SHORT).show(); }
59
15-5 簡訊與定位服務-GPS間諜簡訊 步驟四:建立BroadcastReceiver類別接收簡訊-1
在Android應用程式可以使用廣播接收器接收行動裝置收到簡訊的系統廣播,然後過濾簡訊找出內容為暗號的簡訊,如果是間諜簡訊,就取得目前的定位位置,然後回覆簡訊,其內容是經緯度座標。 Android Studio專案Ch15_5建立SMSReceiver.java類別檔的廣播接收器,如下所示: public class SMSReceiver extends BroadcastReceiver { … }
60
15-5 簡訊與定位服務-GPS間諜簡訊 步驟四:建立BroadcastReceiver類別接收簡訊-2
onReceive()方法 讀取簡訊內容來檢查是否是擁有暗號的簡訊,如下所示: @Override public void onReceive(Context context, Intent intent) { if(intent.getAction().equalsIgnoreCase( "android.provider.Telephony.SMS_RECEIVED")) { SmsMessage[] messages = getMessagesFromIntent(intent); if(messages != null){ for(int i = 0; i < messages.length; i++){ SmsMessage message = messages[i]; if(matchesSpyMessage( context,message.getDisplayMessageBody())){ Log.i("Ch15_5", "收到間諜簡訊!"); sendSpySms(context, message.getOriginatingAddress()); break; }
61
15-5 簡訊與定位服務-GPS間諜簡訊 步驟四:建立BroadcastReceiver類別接收簡訊-3
getMessagesFromIntent()方法 在自訂的getMessagesFromIntent()方法可以取得簡訊內容,參數是Intent物件,傳回值是SmsMessage[]陣列,如下所示: private SmsMessage[] getMessagesFromIntent(Intent intent) { SmsMessage retMsgs[] = null; Bundle bundle = intent.getExtras(); try { Object pdus[] = (Object[]) bundle.get("pdus"); retMsgs = new SmsMessage[pdus.length]; for (int n = 0; n < pdus.length; n++) { byte[] byteData = (byte[]) pdus[n]; retMsgs[n] = SmsMessage.createFromPdu(byteData); } } catch (Exception e) { Log.e("Ch15_5", "取得簡訊內容失敗...", e); return retMsgs;
62
15-5 簡訊與定位服務-GPS間諜簡訊 步驟四:建立BroadcastReceiver類別接收簡訊-4
matchesSpyMessage()方法 在自訂matchesSpyMessage()方法的參數是Context物件和簡訊內容的String字串,方法讀取使用者偏好設定的暗號來比對是否是一則間諜簡訊,如下所示: private boolean matchesSpyMessage(Context context, String message) { SharedPreferences preferences = context.getSharedPreferences( Ch15_5Activity.PREFERENCES, Context.MODE_PRIVATE); String code = preferences.getString( Ch15_5Activity.PREFERENCES_CODE, Ch15_5Activity.PREFERENCES_CODE_DEFAULT); return code.equalsIgnoreCase(message); }
63
15-5 簡訊與定位服務-GPS間諜簡訊 步驟四:建立BroadcastReceiver類別接收簡訊-5
sendSpySms()方法 當確認暗號正確是一則間諜簡訊,我們就呼叫自訂sendSpySms()方法回覆行動裝置經緯度座標的簡訊,如下所示: private void sendSpySms(Context context, String phoneNum) { LocationManager manager; Location current; String best; manager = (LocationManager) context.getSystemService( Context.LOCATION_SERVICE); 上述程式碼取得定位服務的LoactionManager物件後,建立Criteria物件取得最佳的定位提供者,如下所示: Criteria criteria = new Criteria(); best = manager.getBestProvider(criteria, true); current = manager.getLastKnownLocation(best);
64
15-5 簡訊與定位服務-GPS間諜簡訊 步驟四:建立BroadcastReceiver類別接收簡訊-6
然後使用StringBuffer物件的append()方法新增徑度和緯度來建立簡訊內容的Uri字串,如下所示: if (current != null) { StringBuffer sb = new StringBuffer(); sb.append("geo:"); sb.append(current.getLatitude()); sb.append(","); sb.append(current.getLongitude()); String message = sb.toString(); SmsManager sms = SmsManager.getDefault(); sms.sendTextMessage(phoneNum, null, message, null, null); Log.i("Ch15_5", "送出簡訊:'" + message + "'至電話:" + phoneNum); } else Log.e("Ch15_5", "取得GPS位置失敗...");
65
15-5 簡訊與定位服務-GPS間諜簡訊 步驟五:在AndroidManifest.xml註冊廣播接收器和新增權限1
SMSReceiver廣播接收器需要在AndroidManifest.xml檔註冊,Telephony.SMS_RECEIVED是處理行動裝置收到簡訊的系統廣播,如下所示: <receiver android:name=".SMSReceiver" android:enabled="true" android:exported="true" > <intent-filter> <action android:name= "android.provider.Telephony.SMS_RECEIVED" /> </intent-filter> </receiver>
66
15-5 簡訊與定位服務-GPS間諜簡訊 步驟五:在AndroidManifest.xml註冊廣播接收器和新增權限2
<uses-permission android:name="android.permission.SEND_SMS" /> <uses-permission android:name="android.permission.RECEIVE_SMS" /> <uses-permission android:name= "android.permission.ACCESS_FINE_LOCATION"/>
67
End
Similar presentations