Android--手机卫士涉及的知识点总结(二)

简介: 短信拦截:开启服务并在里面注册一个广播接收者 ? 1 2 3 开启服务: Intent intent=new Intent(SettingActivity.

短信拦截:开启服务并在里面注册一个广播接收者

?
1
2
3
开启服务:
Intent intent= new Intent(SettingActivity. this ,CallSmsSafeService. class );
     startService(intent);

//服务里面代码动态注册一个广播接收者

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class CallSmsSafeService extends Service {
     private BlackNumberDao dao;
     private InnerReceiver receiver;
     @Override
     public IBinder onBind(Intent intent) {
         return null ;
     }
     @Override
     public void onCreate() {
         dao= new BlackNumberDao( this );
     //动态注册
         receiver= new InnerReceiver();
         IntentFilter filter= new IntentFilter();
         //设置关心短信到来的动作
         filter.addAction( "android.provider.Telephony.SMS_RECEIVED" );
         filter.setPriority(Integer.MAX_VALUE);
         //代码注册广播接收者
         registerReceiver(receiver, filter);
         System.out.println( "黑名单短信拦截开启了!!!!!" );
         super .onCreate();
 
     }
 
     @Override
     public void onDestroy() {
         super .onDestroy();
         unregisterReceiver(receiver);
         receiver= null ;
     }
     //内部类广播接收者
     private class InnerReceiver extends BroadcastReceiver{
         @Override
         public void onReceive(Context context, Intent intent) {
             //拦截短信
             Object[] objs=(Object[]) intent.getExtras().get( "pdus" );
             for (Object obj:objs){
                 SmsMessage smsMessage=SmsMessage.createFromPdu(( byte [])obj);
                 String address=smsMessage.getOriginatingAddress();
                 String result=dao.find(address);
                 if ( "2" .equals(result)|| "3" .equals(result)){
                     System.out.println( "黑名单短信拦截模式。。。" );
                     abortBroadcast();
                 }
                 //智能拦截
                 String body=smsMessage.getMessageBody();
                 if (body.contains( "天使" )){ //分词算法
                     SmsManager.getDefault().sendTextMessage( "13531829360" , null , "帮你拦截了天使客一条消息" , null , null );
 
                     abortBroadcast();
                 }
             }
         }
     }
}

服务断电就会自动停止,用sp存储不会保存状态,读取系统的的运行信息,调用系统的活动和服务管理者ActivityManager可以判断服务是否正在后台运行

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
  * 判断系统的服务是否在后台运行
  * context:上下文
  * StringName: 服务的全路经名
  */
public static boolean isServiceRunning(Context context,String StringName){
 
     ActivityManager am=(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
     List<runningserviceinfo> infos=am.getRunningServices( 100 );
     for (RunningServiceInfo info:infos){
             String className=info.service.getClassName();
             if (StringName.equals(className)){
                 return true ;
             }
     }
     return false ;
}
</runningserviceinfo>

分词算法:
开源算法:
luncence

利用反射原理挂断电话

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
  * 挂断电话的方法,利用反射
  */
public void endCall() {
     try {
         Class clazz=CallSmsSafeService. class .getClassLoader().loadClass( "android.os.ServiceManager" );
         Method method=clazz.getDeclaredMethod( "getService" , String. class );
         IBinder ibinder=(IBinder) method.invoke( null , TELEPHONY_SERVICE);
         ITelephony iTelephony=ITelephony.Stub.asInterface(ibinder);
         iTelephony.endCall();
 
 
     } catch (Exception e) {
         e.printStackTrace();
     }
}

删除通话的记录(内容观察者)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//监视呼叫记录的的数据库,看什么时候生成了,
//就把它删除
Uri uri=Uri.parse( "content://call_log/calls" );
getContentResolver().registerContentObserver(uri, true , new ContentObserver( new Handler()) {
 
     @Override
     public void onChange( boolean selfChange) {
         super .onChange(selfChange);
         deleteCallLog(incomingNumber);
     }
});
 
 
/**
  * 删除拨号记录
  * @param incomingNumber
  */
public void deleteCallLog(String incomingNumber) {
 
     ContentResolver resolver=getContentResolver();
     Uri uri=Uri.parse( "content://call_log/calls" );
     resolver.delete(uri, "number=?" , new String[]{incomingNumber});
}
<h2 id="打断点看内存查 源码">打断点、看内存、查源码

电话的拦截功能:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
     /**
  * 定义电话管理的服务
  */
private TelephonyManager tm;
private MyPhoneStateListener listener;
 
     /**
      * 实例化电话管理的服务
      */
     tm=(TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
     //注册电话的监听器
     listener= new MyPhoneStateListener();
     //监听电话的状态的改变
     tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);

监听器的注册

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class MyPhoneStateListener extends PhoneStateListener{
 
     @Override
     public void onCallStateChanged( int state, String incomingNumber) {
         super .onCallStateChanged(state, incomingNumber);
 
         switch (state){
         case TelephonyManager.CALL_STATE_IDLE: //空闲状态
             break ;
 
         case TelephonyManager.CALL_STATE_RINGING: //响铃状态
 
             String mode=dao.find(incomingNumber);
             if (mode.equals( "1" )||mode.equals( "3" )){
                 System.out.println( "挂断电话" );
 
             }
 
             break ;
 
         case TelephonyManager.CALL_STATE_OFFHOOK: //接听状态
             break ;
 
         }
     }
 
}

ActivityManager:获取进程和服务的管理

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE) ;   
 
//获得系统运行的进程 
List appList1 = mActivityManager 
         .getRunningAppProcesses(); 
for (RunningAppProcessInfo running : appList1) { 
     System.out.println(running.processName); 
System.out.println( "================" ); 
 
//获得当前正在运行的service 
List appList2 = mActivityManager 
         .getRunningServices( 100 ); 
for (ActivityManager.RunningServiceInfo running : appList2) { 
     System.out.println(running.service.getClassName()); 
 
System.out.println( "================" ); 
 
//获得当前正在运行的activity 
List appList3 = mActivityManager 
         .getRunningTasks( 1000 ); 
for (ActivityManager.RunningTaskInfo running : appList3) { 
     System.out.println(running.baseActivity.getClassName()); 
System.out.println( "================" ); 
 
//获得最近运行的应用 
List appList4 = mActivityManager 
         .getRecentTasks( 100 , 1 ); 
for (ActivityManager.RecentTaskInfo running : appList4) { 
     System.out.println(running.origActivity.getClassName()); 
    
</activitymanager.recenttaskinfo></activitymanager.runningtaskinfo></activitymanager.runningserviceinfo></activitymanager.runningappprocessinfo>

判断某个进程或服务是否在后台进行的工具类:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.cca.mobilephone.Utils;
import java.util.List;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.content.Context;
public class ServicerUtils {
 
/**
  * 判断系统的服务是否在后台运行
  */
public static boolean isServiceRunning(Context context,String StringName){
 
     ActivityManager am=(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
     List<runningserviceinfo> infos=am.getRunningServices( 1000 );
     for (ActivityManager.RunningServiceInfo info:infos){
 
             String className=info.service.getClassName();
             System.out.println(className);
             if (StringName.equals(className)){
                 System.out.println(className);
                 return true ;
             }
     }
     return false ;
}
</runningserviceinfo>

}

数据库的增删改查

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package com.cca.mobilephone.db.dao;
 
import java.util.ArrayList;
import java.util.List;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
 
import com.cca.mobilephone.db.BlackNumberOpenHeloper;
import com.cca.mobilephone.domain.BlackNumberInfo;
 
public class BlackNumberDao {
 
private BlackNumberOpenHeloper openhelper;
 
/**
  * 数据库的构造函数
  * @param context
  */
public BlackNumberDao(Context context) {
     super ();
     openhelper= new BlackNumberOpenHeloper(context);
}
 
 
 
/**
  * 往数据库中增加号码
  * @param phone 增加的电话号码
  * @param mode  模式
  * @return
  */
public boolean add(String phone,String mode){
     SQLiteDatabase db=openhelper.getWritableDatabase();    
     ContentValues values= new ContentValues();
     values.put( "phone" , phone);
     values.put( "mode" , mode);
 
     long id=db.insert( "blacknumberinfo" , null , values);
     db.close();
     if (id!=- 1 ){
         return true ;
     } else {
     return false ;
     }
 
}
 
 
/**
  * 修改黑名单的拦截模式
  * @param phone 要修改的黑名单号码
  * @param newmode 新的拦截模式
  * @return 修改是否成功
  */
public boolean update(String phone,String newmode){
 
     SQLiteDatabase db=openhelper.getWritableDatabase();
     ContentValues values= new ContentValues();
     values.put( "mode" , newmode);
     int rowcount=db.update( "blacknumberinfo" , values, "phone=?" , new String[]{phone});
     db.close();
     if (rowcount== 0 ){
         return false ;
     } else {
         return true ;
     }
}
/**
  * 查找黑名单号码的拦截模式
  * @param phone 要查找的电话号码
  * @return  返回拦截的模式
  */
public String find(String phone){
     String mode= null ;
     SQLiteDatabase db=openhelper.getReadableDatabase();
     Cursor cursor=db.query( "blacknumberinfo" , null , "phone=?" , new String[]{phone}, null , null , null );
     if (cursor.moveToNext()){
         mode=cursor.getString(cursor.getColumnIndex( "mode" ));;
     }
     cursor.close();
     db.close();
     return mode;
 
}
 
/**
  * 删除黑名单号码
  * @param phone  要删除的号码
  * @return  是否删除成功
  */
 
public boolean delete(String phone){
     SQLiteDatabase db=openhelper.getWritableDatabase();
     int rowcount=db.delete( "blacknumberinfo" , "phone=?" , new String[]{phone});
     db.close();
     if (rowcount== 0 ){
         return false ;
     }{
         return true ;
     }
}
/**
  * 返回全部的黑名单信息
  * @return
  */
public List<blacknumberinfo> findAll(){
 
     SQLiteDatabase db=openhelper.getReadableDatabase();
     Cursor cursor=db.query( "blacknumberinfo" , null , null , null , null , null , "_id desc" );
     List<blacknumberinfo> infos= new ArrayList<blacknumberinfo>();
     while (cursor.moveToNext()){
         String phone=cursor.getString(cursor.getColumnIndex( "phone" ));
         String mode=cursor.getString(cursor.getColumnIndex( "mode" ));
         BlackNumberInfo info= new BlackNumberInfo();
         info.setPhone(phone);
         info.setMode(mode);
         infos.add(info);
     }
     cursor.close();
     db.close();
     return infos;
}
</blacknumberinfo></blacknumberinfo></blacknumberinfo>

分批加载

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
  * 分批加载返回的黑名单信息
  * @return
  */
public List<blacknumberinfo> findPart( int startIndex, int maxCount){
 
     SQLiteDatabase db=openhelper.getReadableDatabase();
     Cursor cursor=db.rawQuery( "select _id,phone,mode from blacknumberinfo order by _id desc limit ? offset ?" , new String[]{
             String.valueOf(maxCount),String.valueOf(startIndex)
     });
 
     List<blacknumberinfo> infos= new ArrayList<blacknumberinfo>();
     while (cursor.moveToNext()){
         String phone=cursor.getString(cursor.getColumnIndex( "phone" ));
         String mode=cursor.getString(cursor.getColumnIndex( "mode" ));
         BlackNumberInfo info= new BlackNumberInfo();
         info.setPhone(phone);
         info.setMode(mode);
         infos.add(info);
     }
     cursor.close();
     db.close();
     return infos;
}
</blacknumberinfo></blacknumberinfo></blacknumberinfo>

分页加载解决内存溢出

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
  * 分页加载返回的黑名单信息
  * @return
  */
public List<blacknumberinfo> findPagper( int pagper){
     SQLiteDatabase db=openhelper.getReadableDatabase();
     Cursor cursor=db.rawQuery( "select _id,phone,mode from blacknumberinfo order by _id desc limit ? offset ?" , new String[]{
             String.valueOf( 10 ),String.valueOf(pagper* 10 )
     });
 
     List<blacknumberinfo> infos= new ArrayList<blacknumberinfo>();
     while (cursor.moveToNext()){
         String phone=cursor.getString(cursor.getColumnIndex( "phone" ));
         String mode=cursor.getString(cursor.getColumnIndex( "mode" ));
         BlackNumberInfo info= new BlackNumberInfo();
         info.setPhone(phone);
         info.setMode(mode);
         infos.add(info);
     }
     cursor.close();
     db.close();
     return infos;
}
 
 
 
/**
  * 获取全部总条目
  * @return
  */
 
public int getTotalCount(){
 
     SQLiteDatabase db=openhelper.getReadableDatabase();
     Cursor cursor=db.rawQuery( "select count(*) from blacknumberinfo " , null );
 
     cursor.moveToNext();
     int total=cursor.getInt( 0 );
     cursor.close();
     db.close();
     return total;
}
}
</blacknumberinfo></blacknumberinfo></blacknumberinfo>

复制资产目录下的文件到android系统下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
     /**
  * 拷贝资产目录下的数据库到Android系统下
  */
private void copyDB( final String name) {
 
     /*
      * 数据库多时可能耗时
      */
     new Thread(){
         public void run() {
             File file= new File(getFilesDir(),name);
             if (file.exists()&&file.length()> 0 ){
             System.out.println( "数据库已经加载过,无需在加载!" );
             } else {
 
             try {
                 InputStream is=getAssets().open(name);
                 FileOutputStream fos= new FileOutputStream(file);
                 byte [] buffer= new byte [ 1024 ];
                 int len=- 1 ;
                 while ((len=is.read(buffer))!=- 1 ){
                     fos.write(buffer, 0 , len);
                 }
                 is.close();
                 fos.close();
 
             } catch (Exception e) {
                 e.printStackTrace();
             }
             }
         };
     }.start();
}

自定义吐司

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
     /**
  * 自定义吐司
  * @param address
  */
public void showToast(String address) {
     WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
     View view = View.inflate(getApplicationContext(), R.layout.item_toast, null );
     //设置背景,字体等自定义属性
     int which=getSharedPreferences( "config" , 0 ).getInt( "which" , 0 );
     int bgs[]={R.drawable.btn_gray_normal,R.drawable.btn_green_normal,R.drawable.btn_gray_pressed,R.drawable.call_show_bg,R.drawable.btn_disabled};
     view.setBackgroundResource(bgs[which]);
 
     TextView tv_address=(TextView) view.findViewById(R.id.tv_address);
     tv_address.setText(address);
//设置参数params
     WindowManager.LayoutParams params = new WindowManager.LayoutParams();
      params.height = WindowManager.LayoutParams.WRAP_CONTENT;
      params.width = WindowManager.LayoutParams.WRAP_CONTENT;
      params.format = PixelFormat.TRANSLUCENT;
      params.type = WindowManager.LayoutParams.TYPE_TOAST;
      params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
              | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
              | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
     wm.addView(view, params);
 
}

及时退出吐司的显示用:wm.removeView(view);

控件的拖拽效果

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
ImageView imgview= (ImageView) findViewById(R.id.imageview);
imgview.setOnTouchListener( new OnTouchListener() {
         int startx;
         int starty;
         @Override
         public boolean onTouch(View v, MotionEvent event) {
 
             switch (event.getAction()){
             case MotionEvent.ACTION_DOWN: //手指第一次触摸控件时调用
                 //获取控件在屏幕上的坐标
                 startx=( int ) event.getRawX();
                 starty=( int ) event.getRawY();
                 break ;
 
             case MotionEvent.ACTION_MOVE: //手指在控件上移动的事件
                 //手指移动后的偏移量
                 int newx=( int ) event.getRawX();
                 int newy=( int ) event.getRawY();
                 int dx=newx-startx;
                 int dy=newy-starty;
                 //移动后的控件新坐标
                 imgview.layout(imgview.getLeft()+dx, imgview.getTop()+dy,
                                 imgview.getRight()+dx, imgview.getBottom()+dy);
                 //移动后重新初始化控件坐标
                 startx=( int ) event.getRawX();
                 starty=( int ) event.getRawY();
                 System.out.println( "移动了控件" +startx+ "---" +starty);
                 break ;
 
             case MotionEvent.ACTION_UP: //手指离开控件的一瞬间
 
                 break ;
             }
             return true ;
 
 
         }
     });

简单双击效果实现

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
btn=(Button) findViewById(R.id.btn);
     btn.setOnClickListener( new OnClickListener() {
         @Override
         public void onClick(View v) {
             if (firsttime> 0 ){
                 secondtime=System.currentTimeMillis();
                 if ((secondtime-firsttime)< 500 ){
                     Toast.makeText(getApplicationContext(), "双击了" , 0 ).show();
                     firsttime= 0 ;
                 } else {
                     firsttime= 0 ;
                 }
                 return ;
             }
             firsttime=System.currentTimeMillis();
             new Thread(){
                 public void run() {
                     try {
                         Thread.sleep( 500 );
                         firsttime= 0 ;
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                 };
             }.start();
         }
     });

多次点击事件实现

?
1
2
3
4
5
6
7
8
9
10
11
12
//定义了多长的数组就是多次点击,3就是连续3击   
private long [] mHits= new long [ 3 ];
/**
*四个参数:源数组,从第几个开始拷贝,目标数组,从第几个开始拷贝,拷贝的长度
*
*/
System.arraycopy(mHits, 1 , mHits, 0 , mHits.length- 1 );
mHits[mHits.length- 1 ] = SystemClock.uptimeMillis();
if (mHits[ 0 ] >= (SystemClock.uptimeMillis()- 500 )) {
 
     Toast.makeText(getApplicationContext(), "多次击了" , 0 ).show();
}

自定义吐司加上拖拽的效果图显示

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
     /**
  * 自定义吐司
  * @param address
  */
public void showToast(String address) {
     wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
     view = View.inflate(getApplicationContext(), R.layout.item_toast, null );
 
     view.setOnTouchListener( new OnTouchListener() {
         int startx ;
         int starty ;
 
         @SuppressWarnings ( "deprecation" )
         @Override
         public boolean onTouch(View v, MotionEvent event) {
 
             switch (event.getAction()){
             case MotionEvent.ACTION_DOWN: //手指触摸
                 //获取自定义吐司坐标
                 startx=( int ) event.getRawX();
                 starty=( int ) event.getRawY();
 
                 break ;
             case MotionEvent.ACTION_UP: //手指离开
                 //存储控件的位置坐标
                  SharedPreferences sp = getSharedPreferences( "config" , MODE_PRIVATE);
                 Editor edit=sp.edit();
                 edit.putInt( "lastx" , params.x);
                 edit.putInt( "lasty" , params.y);
                 edit.commit();
 
                 break ;
             case MotionEvent.ACTION_MOVE: //手指移动
                 //获取偏移量
                 int newx=( int ) event.getRawX();
                 int newy=( int ) event.getRawY();
                 int dx=newx-startx;
                 int dy=newy-starty;
                 params.x +=dx;
                 params.y +=dy;
                 //判断view控件是否移出屏幕范围
                 if (params.x>(wm.getDefaultDisplay().getWidth()-view.getWidth())){
                     params.x=wm.getDefaultDisplay().getWidth()-view.getWidth();
                 }
                 if (params.y>(wm.getDefaultDisplay().getHeight()-view.getHeight())){
                     params.x=wm.getDefaultDisplay().getHeight()-view.getHeight();
                 }
 
                 wm.updateViewLayout(view, params);
                 //重新初始化控件坐标
                 startx=( int ) event.getRawX();
                 starty=( int ) event.getRawY();
                 break ;
             }
 
             return true ;
         }
     });
     //设置背景颜色
     int which=getSharedPreferences( "config" , 0 ).getInt( "which" , 0 );
     int bgs[]={R.drawable.btn_gray_normal,R.drawable.btn_green_normal,R.drawable.btn_gray_pressed,R.drawable.call_show_bg,R.drawable.btn_disabled};
     view.setBackgroundResource(bgs[which]);
 
     TextView tv_address=(TextView) view.findViewById(R.id.tv_address);
     tv_address.setText(address);
     params = new WindowManager.LayoutParams();
      params.height = WindowManager.LayoutParams.WRAP_CONTENT;
      params.width = WindowManager.LayoutParams.WRAP_CONTENT;
      params.format = PixelFormat.TRANSLUCENT;
 
      //左上对齐
      params.gravity=Gravity.LEFT+Gravity.TOP;
      SharedPreferences sp=getSharedPreferences( "config" , MODE_PRIVATE);
      params.x=sp.getInt( "lastx" , 0 );
      params.y=sp.getInt( "lasty" , 0 );
      params.type = WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
      params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
              | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 
     wm.addView(view, params);
 
}

目录
相关文章
|
2月前
|
监控 安全 Android开发
【新手必读】Airtest测试Android手机常见的设置问题
【新手必读】Airtest测试Android手机常见的设置问题
|
2月前
|
机器学习/深度学习 人工智能 Android开发
安卓智能手机操作系统演化史
【2月更文挑战第5天】 本文通过对安卓智能手机操作系统的演化历程进行探讨,分析了安卓系统从诞生至今的发展脉络和关键技术革新,从最初的版本到如今的最新版本,探讨了其在移动互联网时代的重要作用,以及未来可能的发展方向。
|
3月前
|
JavaScript Android开发
手机也能搭建个人博客?安卓Termux+Hexo搭建属于你自己的博客网站
手机也能搭建个人博客?安卓Termux+Hexo搭建属于你自己的博客网站
36 0
|
1月前
|
Web App开发 前端开发 网络安全
前端分析工具之 Charles 录制 Android/IOS 手机的 https 应用
【2月更文挑战第21天】前端分析工具之 Charles 录制 Android/IOS 手机的 https 应用
50 1
前端分析工具之 Charles 录制 Android/IOS 手机的 https 应用
|
1月前
|
网络协议 关系型数据库 MySQL
安卓手机termux上安装MariaDB数据库并实现公网环境下的远程连接
安卓手机termux上安装MariaDB数据库并实现公网环境下的远程连接
|
1月前
|
JavaScript Android开发
手机也能轻松搭建个人博客,使用安卓Termux+Hexo建立自己的网站
手机也能轻松搭建个人博客,使用安卓Termux+Hexo建立自己的网站
|
2月前
|
安全 Android开发
如何在Android手机上安装第三方应用?
【2月更文挑战第4天】在Android系统中,安装第三方应用是一个常见的需求。本文将介绍如何在Android手机上安装第三方应用,并提供详细的步骤和注意事项。
157 2
|
3月前
|
安全 网络协议 Linux
【公网远程手机Android服务器】安卓Termux搭建Web服务器
【公网远程手机Android服务器】安卓Termux搭建Web服务器
63 0
|
4月前
|
Android开发
安卓手机快速过检测完成某某学习
安卓手机快速过检测完成某某学习
22 0
|
4月前
|
传感器 物联网 Android开发
【Android App】物联网中查看手机支持的传感器及实现摇一摇功能-加速度传感器(附源码和演示 超详细)
【Android App】物联网中查看手机支持的传感器及实现摇一摇功能-加速度传感器(附源码和演示 超详细)
67 1