一、排坑
短信测试
用模拟器
启动界面无设备显示
重启电脑
adb测试插拔sd卡
命令找不到。。
发送广播闪退
系统广播,非系统应用无权限发送这个广播
无法接收广播
用动态注册
监听卸载广播要加
filter.addDataScheme("package");
二、IP拨号器
接收拨打电话的广播,修改广播内携带的电话号码
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.PROCESS_OUTGOING_CALLS)!= PackageManager.PERMISSION_GRANTED){ //申请权限 ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.PROCESS_OUTGOING_CALLS},1); }else { //把动作告诉系统 } } public void click(View v){ EditText et = (EditText) findViewById(R.id.et); SharedPreferences sp = getSharedPreferences("ip", MODE_PRIVATE); sp.edit().putString("ipNumber", et.getText().toString()).commit(); } public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode){ case 1: //发短信权限回调 if (grantResults[0]==PackageManager.PERMISSION_GRANTED){ }else { //提示用户权限未被授予 Log.d("MainActivity","未授予权限"); exit(); } break; } } public void exit() { MainActivity.this.finish(); System.exit(0); } }
public class CallReceiver extends BroadcastReceiver { private static final String TAG = "CallReceiver"; //接收到广播时就会调用 @Override public void onReceive(Context context, Intent intent) { //添加IP线路 //在打电话广播中,会携带拨打的电话的号码,通过以下代码获取到 String number = getResultData(); Log.e(TAG, "onReceive: " ); if(number.startsWith("0")){ SharedPreferences sp = context.getSharedPreferences("ip", Context.MODE_PRIVATE); String ipNumber = sp.getString("ipNumber", ""); //把IP线路号码添加至用户拨打号码的前面 number = ipNumber + number; //把新的号码重新放入广播中 setResultData(number); abortBroadcast(); } } }
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.index42.ipdialer"> <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name=".CallReceiver"> <intent-filter> <action android:name="android.intent.action.NEW_OUTGOING_CALL"/> </intent-filter> </receiver> </application> </manifest>
三、短信拦截器
-
4.0以后广播接收者安装以后必须手动启动一次,否则不生效
- 4.0以后广播接收者如果被手动关闭,就不会再启动了
- 系统创建广播时,把短信存放到一个数组,然后把数据以pdus为key存入bundle,再把bundle存入intent
-
清单文件中配置广播接收者接收的广播类型,注意要设置优先级属性,要保证优先级高于短信应用,才可以实现拦截
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.RECEIVE_SMS)!= PackageManager.PERMISSION_GRANTED){ //申请权限 ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.RECEIVE_SMS,Manifest.permission.SEND_SMS,Manifest.permission.READ_PHONE_STATE},1); }else { //把动作告诉系统 } } public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode){ case 1: //发短信权限回调 if (grantResults[0]==PackageManager.PERMISSION_GRANTED&&grantResults[1]==PackageManager.PERMISSION_GRANTED&&grantResults[2]==PackageManager.PERMISSION_GRANTED){ }else { //提示用户权限未被授予 exit(); Log.d("MainActivity","未授予发短信权限"); } break; } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } public void exit() { MainActivity.this.finish(); System.exit(0); } }
public class SmsReceiver extends BroadcastReceiver { private static final String TAG = "SmsReceiver"; @Override public void onReceive(Context context, Intent intent) { //拿到短信的信息 //短信内容封装在intent中 Bundle bundle = intent.getExtras(); //以pdus为键,取出一个object数组,数组中的每一个元素,都是一条短信 Object[] objects = (Object[]) bundle.get("pdus"); int currentApiVversion = Build.VERSION.SDK_INT; //拿到广播中的所有短信 for (Object object : objects) { //通过pdu来构造短信 SmsMessage sms = SmsMessage.createFromPdu((byte[])object); // if(currentApiVversion >= Build.VERSION_CODES.LOLLIPOP) // sms = SmsMessage.createFromPdu((byte[])object, Telephony.Sms.Intents.SMS_RECEIVED_ACTION); // else // sms = SmsMessage.createFromPdu((byte[])object); Log.e(TAG, "onReceive!!! "); if(sms.getOriginatingAddress().equals("131")){ //阻止其他广播接收者收到这条广播 abortBroadcast(); SmsManager.getDefault().sendTextMessage(sms.getOriginatingAddress(), null, "你是个好人", null, null); } // System.out.println(sms.getMessageBody()); } } }
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.index42.smslanjie"> <uses-permission android:name="android.permission.RECEIVE_SMS"/> <uses-permission android:name="android.permission.SEND_SMS"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name=".SmsReceiver"> <intent-filter android:priority="1000"> <action android:name="android.provider.Telephony.SMS_RECEIVED"/> </intent-filter> </receiver> </application> </manifest>
四、监听SD卡状态
-
清单文件中定义广播接收者接收的类型,监听SD卡常见的三种状态,所以广播接收者需要接收三种广播
<receiver android:name="com.itheima.sdcradlistener.SDCardReceiver"> <intent-filter > <action android:name="android.intent.action.MEDIA_MOUNTED"/> <action android:name="android.intent.action.MEDIA_UNMOUNTED"/> <action android:name="android.intent.action.MEDIA_REMOVED"/> <data android:scheme="file"/> </intent-filter> </receiver>
-
广播接收者的定义
public class SDCardReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 区分接收到的是哪个广播 String action = intent.getAction(); if(action.equals("android.intent.action.MEDIA_MOUNTED")){ System.out.println("sd卡就绪"); } else if(action.equals("android.intent.action.MEDIA_UNMOUNTED")){ System.out.println("sd卡被移除"); } else if(action.equals("android.intent.action.MEDIA_REMOVED")){ System.out.println("sd卡被拔出"); } } }
五、勒索软件
- 接收开机广播,在广播接收者中启动勒索的Activity
-
清单文件中配置接收开机广播
- 广播接收者的启动,并不会创建任务栈,那么没有任务栈,就无法启动activity
-
手动设置创建新任务栈的flag
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public void onBackPressed() { // TODO Auto-generated method stub // super.onBackPressed(); } }
public class BootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 启动Activity,实现开机自动启动勒索软件 Intent it = new Intent(context, MainActivity.class); //创建任务栈存放启动的Activity it.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(it); } }
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.index42.lesuo"> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name=".BootReceiver"> <intent-filter > <action android:name="android.intent.action.BOOT_COMPLETED"/> </intent-filter> </receiver> </application> </manifest>
六、监听应用的安装、卸载、更新
原理:应用在安装卸载更新时,系统会发送广播,广播里会携带应用的包名
public class MainActivity extends Activity { private static final String TAG = "MainActivity"; private APPStatusReceiver receiver; @Override protected void onCreate(Bundle savedInstanceState) { Log.e(TAG, "onCreate: "); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); receiver = new APPStatusReceiver(); IntentFilter filter=new IntentFilter(); // filter.addAction("android.intent.action.SCREEN_ON"); // filter.addAction("android.intent.action.HEADSET_PLUG"); filter.addAction("android.intent.action.PACKAGE_ADDED"); filter.addAction("android.intent.action.PACKAGE_REPLACED"); filter.addAction("android.intent.action.PACKAGE_REMOVED"); filter.addAction("android.intent.action.PACKAGE_FULLY_REMOVED"); filter.addDataScheme("package"); registerReceiver(receiver, filter); } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(receiver); } }
public class APPStatusReceiver extends BroadcastReceiver { private static final String TAG = "APPStatusReceiver"; //@Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub Log.e(TAG, "onReceive: " ); String action = intent.getAction(); Uri uri = intent.getData(); // if (action.equals("android.intent.action.SCREEN_ON")) { // Log.e(TAG, "屏幕亮啦"); // } // if (action.equals("android.intent.action.HEADSET_PLUG")) { // int state = intent.getIntExtra("state", -1); // int mic = intent.getIntExtra("microphone", -1); // if(state==0) Log.e(TAG, "拔出耳机"); // if(state==1) Log.e(TAG, "插入耳机"); // } if("android.intent.action.PACKAGE_ADDED".equals(action)){ Log.e(TAG, uri.toString() + "被安装了"); Toast.makeText(context, uri.toString() + "被安装了", Toast.LENGTH_SHORT).show(); } if("android.intent.action.PACKAGE_REPLACED".equals(action)){ Log.e(TAG, uri.toString() + "被升级了" ); Toast.makeText(context, uri.toString() + "被升级了", Toast.LENGTH_SHORT).show(); } if("android.intent.action.PACKAGE_REMOVED".equals(action)){ Log.e(TAG, uri.toString() + "被卸载了" ); Toast.makeText(context, uri.toString() + "被卸载了", Toast.LENGTH_SHORT).show(); } } }
七、自定义广播
接收者
public class MainActivity extends Activity { private ZDYReceiver zdyReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); zdyReceiver = new ZDYReceiver(); IntentFilter filter=new IntentFilter(); filter.addAction("com.itheima.zdy"); registerReceiver(zdyReceiver, filter); } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(zdyReceiver); } }
public class ZDYReceiver extends BroadcastReceiver { private static final String TAG = "ZDYReceiver"; @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub Log.e(TAG, "成功接收到广播: "); Toast.makeText(context, "成功接收到广播", 0).show(); } }
发送者
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void click(View v){ //发送自定义广播 Intent intent = new Intent(); //广播中的action也是自定义的 intent.setAction("com.itheima.zdy"); sendBroadcast(intent); } }
八、广播类型
- 无序广播:所有跟广播的intent匹配的广播接收者都可以收到该广播,并且是没有先后顺序(同时收到)
- 有序广播:所有跟广播的intent匹配的广播接收者都可以收到该广播,但是会按照广播接收者的优先级来决定接收的先后顺序
- 优先级的定义:-1000~1000
- 最终接收者:所有广播接收者都接收到广播之后,它才接收,并且一定会接收
- abortBroadCast:阻止其他接收者接收这条广播,类似拦截,只有有序广播可以被拦截
接收者
public class MainActivity extends Activity { private ShengZF shengZF; private ShiZF shiZF; private XianZF xianZF; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); shengZF = new ShengZF(); shiZF = new ShiZF(); xianZF = new XianZF(); IntentFilter filter=new IntentFilter(); filter.addAction("com.itheima.fdm"); filter.setPriority(1000); registerReceiver(shengZF, filter); filter.setPriority(800); registerReceiver(shiZF, filter); filter.setPriority(600); registerReceiver(xianZF, filter); } }
public class ShengZF extends BroadcastReceiver { private static final String TAG = "ShengZF"; @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub String text = getResultData(); Log.e(TAG, "省*收到文件: " + text); System.out.println("省*收到文件:" + text); setResultData("每人发80斤大米"); } }
public class ShiZF extends BroadcastReceiver { private static final String TAG = "ShiZF"; @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub String text = getResultData(); Log.e(TAG, "市*收到文件: " + text); System.out.println("市*收到文件:" + text); abortBroadcast(); } }
public class XianZF extends BroadcastReceiver { private static final String TAG = "XianZF"; @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub String text = getResultData(); Log.e(TAG, "县*收到文件:" + text); System.out.println("县*收到文件:" + text); } }
发送者
public class MainActivity extends Activity { private static final String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void click(View v){ Intent intent = new Intent(); intent.setAction("com.itheima.fdm"); //发送有序广播 //resultReceiver:不需要在清单文件中配置,这个广播接收者只接受该条有序广播,并且是最后一个收到该广播,并且一定可以收到该广播 sendOrderedBroadcast(intent, null, new MyReceiver(), null, 0, "每人发100斤大米", null); } // class MyReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { String text = getResultData(); Log.e(TAG, "反贪局收到文件:" + text); System.out.println("反贪局收到文件:" + text); } } }
九、服务
Service
- 就是默默运行在后台的组件,可以理解为是没有前台的activity,适合用来运行不需要前台界面的代码
- 服务可以被手动关闭,不会重启,但是如果被自动关闭,内存充足就会重启
- startService启动服务的生命周期
- onCreate-onStartCommand-onDestroy
- 重复的调用startService会导致onStartCommand被重复调用
进程优先级
- 前台进程:拥有前台activity(onResume方法被调用)
- 可见进程:拥有可见activity(onPause方法被调用)
- 服务进程:不到万不得已不会被回收,而且即便被回收,内存充足时也会被重启
- 后台进程:拥有后台activity(activity的onStop方法被调用了),很容易被回收
- 空进程:没有运行任何activity,很容易被回收
public class MainActivity extends Activity { private Intent intent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); intent = new Intent(this, MyService.class); } public void click(View v){ //显式启动服务 startService(intent); } public void click2(View v){ //关闭服务 // Intent intent = new Intent(this, MyService.class); stopService(intent); } }
public class MyService extends Service { private static final String TAG = "MyService"; @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub Log.e(TAG, "onBind: "); return null; } @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); Log.e(TAG, "create方法: "); System.out.println("create方法"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub Log.e(TAG, "startCommand方法: "); System.out.println("startCommand方法"); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); Log.e(TAG, "destroy方法: " ); System.out.println("destroy方法"); } }
十、电话qie听器
public class MainActivity extends Activity { private static final String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){ //申请权限 ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.RECORD_AUDIO,Manifest.permission.READ_PHONE_STATE},1); }else { //把动作告诉系统 //send(); } } public void click(View v){ Intent intent = new Intent(this, RecorderService.class); startService(intent); } public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode){ case 1: //发短信权限回调 if (grantResults[0]==PackageManager.PERMISSION_GRANTED&&grantResults[1]==PackageManager.PERMISSION_GRANTED&&grantResults[2]==PackageManager.PERMISSION_GRANTED){ }else { //提示用户权限未被授予 Log.d("MainActivity","未授予权限"); } break; } } }
public class BootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { //启动录音机服务 Intent it = new Intent(context, RecorderService.class); context.startService(it); } }
public class RecorderService extends Service { private MediaRecorder recorder; private TelephonyManager tm; private MyListener listener; private static final String TAG = "RecorderService"; private String path= Environment.getExternalStorageDirectory()+"/ahmk/"; private String filename=path+"luyin.amr"; @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); //拿到电话管理器 tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); //监听电话状态 listener=new MyListener(); //events:决定PhoneStateListener侦听什么内容 tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE); } class MyListener extends PhoneStateListener{ //一旦电话状态改变,此方法调用 @Override public void onCallStateChanged(int state, String incomingNumber) { // TODO Auto-generated method stub super.onCallStateChanged(state, incomingNumber); Log.e(TAG, "onCallStateChanged: "); switch (state) { case TelephonyManager.CALL_STATE_IDLE: Log.e(TAG, "空闲: "); System.out.println("空闲"); if(recorder != null){ recorder.stop(); recorder.release(); recorder = null; } break; case TelephonyManager.CALL_STATE_RINGING: Log.e(TAG, "响铃: " ); System.out.println("响铃"); break; case TelephonyManager.CALL_STATE_OFFHOOK: Log.e(TAG, "摘机: " ); System.out.println("摘机"); //开始录音 if(recorder == null){ recorder = new MediaRecorder(); recorder.setAudioSource(MediaRecorder.AudioSource.MIC); recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); File dir = new File(path); try { if (!dir.exists()) { dir.mkdirs(); } }catch (Exception e) { // TODO Auto-generated catch block Log.e(TAG, e.getMessage()); } recorder.setOutputFile(Environment.getExternalStorageDirectory()+"/ahmk/luyin.amr"); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); try { recorder.prepare(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(recorder != null){ Log.e(TAG, "Start!!!: "); recorder.start(); } break; } } } public void onDestroy() { super.onDestroy(); // 取消电话的监听 tm.listen(listener, PhoneStateListener.LISTEN_NONE); listener = null; } }
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.index42.recorder"> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".RecorderService"></service> <receiver android:name=".BootReceiver"> <intent-filter > <action android:name="android.intent.action.BOOT_COMPLETED"/> </intent-filter> </receiver> </application> </manifest>