//gradle 下载慢 //可以直接下载gradle之后放在对应的目录里
//或者修改 根目录下的文件bulid.gradle ,使用国内阿里云仓库
buildscript {
repositories {
maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
}
}
allprojects {
repositories {
maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
}
}
android Intent 隐式启动和显式启动 activity
1.显式启动 //明确表示要启动的是什么activity,是activity的具体实例
Intent intent =new Intent(this,SecondActivity.class);
startActivity(intent);
2.隐式启动Intent // 只是指定一个action,可能是浏览器动作,可能是打开支付界面动作
Intent intent = new Intent("com.baimasu.kkk");
startActivity(intent);
<activity android:name=".SecondActivity" >
<intent-filter>
<action android:name="com.baimasu.kkk" />
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
3.activity 中 Intent FIlter 匹配过程
// 加载安装的所有的Intent Filter到一个列表
// 去掉action匹配失败的intent filter
// 去掉url数据匹配失败的intent filter
// 去掉category匹配失败的Intent filter
// 剩下的intent filter 数量是否为0
//否
//查找失败,抛出异常
// 是
// 将匹配成功的intent filter安优先级排序
// return 最高优先级的Intent filter
////DynamicLoadApk *///////
宿主里面的activity是:
<activity name="****.proxyActivity >
<action ***/>
<***** />
</activity>
onclick->通过DLIntent传递了要启动的包名和activity名,之后
DLProxyActivity.onCreate() 方法里面调用来了 DLProxyImpl的
impl.onCreate(getIntent()); -->launchTargetActivity();
mClass = intent.getStringExtra(DLConstants.EXTRA_CLASS) //从intent里面得到类名
class<?> localClass = getClassLoader().loadClass(mClass); //加载类
Constructor<?> localConstructor = localClass.getConstructor(new Class[] {}); //得到构造函数
Object instance = localConstructor.newInstance(new Object[] {}); //反射生成实际插件的activity
mPluginActivity = (DLPlugin) instance;
((DLAttachable) mProxyActivity).attach(mPluginActivity, mPluginManager); //代理activity接管插件activity的生命周期
Log.d(TAG, "instance = " + instance);
// attach the proxy activity and plugin package to the mPluginActivity
mPluginActivity.attach(mProxyActivity, mPluginPackage);
Bundle bundle = new Bundle();
bundle.putInt(DLConstants.FROM, DLConstants.FROM_EXTERNAL);
mPluginActivity.onCreate(bundle); // 调用插件activity的onCreate函数,DLConstants.FROM判断是不是动态加载
// DLProxyActivity 作为插件activity的宿主,在宿主中存在,管理插件activity的生命周期
// ProxyActivity 生命周期同步
//在 ProxyActivity 生命周期里用反射调用插件 Activity 相应生命周期的方法,简单粗暴;
//把插件 Activity 的生命周期抽象成接口,在 ProxyActivity 的生命周期里调用;
//dynamic-load-apk 向我们展示了许多优秀的处理方法
把 Activity 关键的生命周期方法抽象成 DLPlugin 接口,ProxyActivity 通过 DLPlugin 代理调用插件 Activity 的生命周期;
设计一个基础的 BasePluginActivity 类,插件项目里使用这些基类进行开发,可以以接近常规 Android 开发的方式开发插件项目;
以类似的方式处理 Service 的问题;
处理了大量常见的兼容性问题(比如使用 Theme 资源时出现的问题);
处理了插件项目里的 so 库的加载问题;
使用 PluginPackage 管理插件 APK,从而可以方便地管理多个插件项目;
http://blog.csdn.net/working_harder/article/details/53204493
http://yuqirong.me/2016/10/29/Dynamic-Load-Apk%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/
//class。forName() 和classLoader 都可以对类进行加载
// class.forName() 除了将类的.class文件加载到jvm中,还会对类进行解析,执行static{}代码
// classLoader只做一件事,就是将.class文件加载jvm中,不会执行static{}代码
// private 类内可见
// protected 包内可见
// public 全部可见
// try{
// Constructor<?> constructor = Activity.class.getConstructor();
// Object o = constructor.newInstance();
// Activity activity = (Activity)o;
// activity.onStart(); /***这里报错了,因为onStart()是protected方法,是包内访问权限,在android.app.Activity里面才可以访问,假如想要访问onStart()方法的话,要反射
// 修改onStart方法的修饰符,将他改为public,所以DLProxyActivity里面才实现了一套public接口来管理生命周期
// }catch (Exception e){
//
// }
//DLProxyActivity假如不通过DLPlugin接口管理生命周期的话
protected void onStop() {
this.mRemoteActivity.onStop(); //报错,访问了android.app.Activity里面的protected方法
super.onStop();
}
//DLBasePluginActivity
public void onStop(){
if(this.mFrom == 0){ // 是自然加载
super.onStop();
}
// 为什么不是自然加载就直接返回了呢,因为此时DLBasePluginActivity只是一个普通的activity对象
//它不应该参与生命周期的管理,//后面的继承于DLBasePluginActivity的可以在这里清除数据,或者修改其它
//例如: this.listViewHashMap.clearALl(); this.state = STATE_STOP,this.registerNotify(***);
}
//同一个class经过不同的类加载器加载是不同的
// gradle ?部分出错了??
// 动态加载时候 ,plugin模块的build.gradle 应该改为
dependencies {
provided fileTree(dir: 'libs', include: ['.jar'])
//provided 意思是编译时候使用,但是不打包到apk中,这样做是因为宿主项目里面已经包含了dl-lib.jar了,
//如果插件也有dl-lib.jar 就会加载两次了,,报错**
//必须使用宿主的DL框架加载plugin
.........
}
// 可以通过gradle来计算bulid时间,或者在bulid过程中执行某些函数,或者排除某些.class不bulid
//execute task after android gradle build
//execute task before android gradle build
//Android uses-feature uses-permission
<uses-feature
android:name="string" //app需要的功能名称
android:required=["true" | "false"]
// true 表示该功能对于app是必须有的,如果某一个设备不具备该功能,
//googlePlay商店将会对该设备隐藏该app
//false 表示该功能对于app来说不是必需的,假如某一个设备不具备该功能
// googlePlay商店依然对该设备显示该app
android:glEsVersion="Integer"
//指定 open GL的版本号,只针对open GL功能 游戏开发时候要使用到openGL
/> // uses-feature 并不获取权限,只是说明该app有着该权限的特征
<uses-permission android:name="String"
// 声明要获取的权限,可以是一个标准的系统权限
// 也可以是app自己定义的一个权限
android:maxSdkVersion="Integer"
// 此权限应授予应用的最高 API 级别。
// 如果应用需要的权限从某个 API 级别开始不再需要,则设置此属性很有用。
// 例如,从 Android 4.4(API 级别 19)开始,
// 应用在外部存储空间写入其特定目录(getExternalFilesDir() 提供的目录)时不再需要请求 WRITE_EXTERNAL_STORAGE 权限。
// 但 API 级别 18 和更低版本需要此权限。
// 因此,您可以使用如下声明,声明只有 API 级别 18 及以前版本才需要此权限:
/>
// uses-feature的作用更像是一个过滤器,
// google play 商店会根据该标签来过滤设备,
// 比如用户在uses-feature中声明了要使用相机,
// 这时候在google play商店中该app就不再对没有照相机的设备显示。
// 但是,如果用户同时也设置了uses-feature的属性android:required 为false的话,
// google play商店仍然会对没有照相机的设备显示该app。
// 假如现在需要开发一个app,它是一个聊天的工具,
// 包含给对方发送照片的功能,所以会用到系统的照相机。
// 但是,该app的主要功能还是聊天,
// 就算是在一个没有照相机的手机上也应该能够让它正常地使用聊天的功能。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.demo" >
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature
android:name="android.hardware.camera"
android:required=false />
</manifest> // 例如:微信?
// android.Manifest
// public static final String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES";
// public static final String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION";
// public static final String ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION";
// public static final String ACCESS_LOCATION_EXTRA_COMMANDS = "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS";
// public static final String ACCESS_NETWORK_STATE = "android.permission.ACCESS_NETWORK_STATE";
// public static final String ACCESS_NOTIFICATION_POLICY = "android.permission.ACCESS_NOTIFICATION_POLICY";
// public static final String ACCESS_WIFI_STATE = "android.permission.ACCESS_WIFI_STATE";
// public static final String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
// public static final String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
// public static final String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS";
// public static final String BATTERY_STATS = "android.permission.BATTERY_STATS";
// public static final String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
// public static final String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
// public static final String BIND_AUTOFILL_SERVICE = "android.permission.BIND_AUTOFILL_SERVICE";
// /** @deprecated */
// @Deprecated
// public static final String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
// public static final String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
// public static final String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
// public static final String BIND_CONDITION_PROVIDER_SERVICE = "android.permission.BIND_CONDITION_PROVIDER_SERVICE";
// public static final String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
// public static final String BIND_DREAM_SERVICE = "android.permission.BIND_DREAM_SERVICE";
// public static final String BIND_INCALL_SERVICE = "android.permission.BIND_INCALL_SERVICE";
// public static final String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
// public static final String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE";
// public static final String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
// public static final String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
// public static final String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
// public static final String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
// public static final String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
// public static final String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
// public static final String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
// public static final String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
// public static final String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
// public static final String BIND_VISUAL_VOICEMAIL_SERVICE = "android.permission.BIND_VISUAL_VOICEMAIL_SERVICE";
// public static final String BIND_VOICE_INTERACTION = "android.permission.BIND_VOICE_INTERACTION";
// public static final String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
// public static final String BIND_VR_LISTENER_SERVICE = "android.permission.BIND_VR_LISTENER_SERVICE";
// public static final String BIND_WALLPAPER = "android.permission.BIND_WALLPAPER";
// public static final String BLUETOOTH = "android.permission.BLUETOOTH";
// public static final String BLUETOOTH_ADMIN = "android.permission.BLUETOOTH_ADMIN";
// public static final String BLUETOOTH_PRIVILEGED = "android.permission.BLUETOOTH_PRIVILEGED";
// public static final String BODY_SENSORS = "android.permission.BODY_SENSORS";
// public static final String BROADCAST_PACKAGE_REMOVED = "android.permission.BROADCAST_PACKAGE_REMOVED";
// public static final String BROADCAST_SMS = "android.permission.BROADCAST_SMS";
// public static final String BROADCAST_STICKY = "android.permission.BROADCAST_STICKY";
// public static final String BROADCAST_WAP_PUSH = "android.permission.BROADCAST_WAP_PUSH";
// public static final String CALL_PHONE = "android.permission.CALL_PHONE";
// public static final String CALL_PRIVILEGED = "android.permission.CALL_PRIVILEGED";
// public static final String CAMERA = "android.permission.CAMERA";
// public static final String CAPTURE_AUDIO_OUTPUT = "android.permission.CAPTURE_AUDIO_OUTPUT";
// public static final String CAPTURE_SECURE_VIDEO_OUTPUT = "android.permission.CAPTURE_SECURE_VIDEO_OUTPUT";
// public static final String CAPTURE_VIDEO_OUTPUT = "android.permission.CAPTURE_VIDEO_OUTPUT";
// public static final String CHANGE_COMPONENT_ENABLED_STATE = "android.permission.CHANGE_COMPONENT_ENABLED_STATE";
// public static final String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION";
// public static final String CHANGE_NETWORK_STATE = "android.permission.CHANGE_NETWORK_STATE";
// public static final String CHANGE_WIFI_MULTICAST_STATE = "android.permission.CHANGE_WIFI_MULTICAST_STATE";
// public static final String CHANGE_WIFI_STATE = "android.permission.CHANGE_WIFI_STATE";
// public static final String CLEAR_APP_CACHE = "android.permission.CLEAR_APP_CACHE";
// public static final String CONTROL_LOCATION_UPDATES = "android.permission.CONTROL_LOCATION_UPDATES";
// public static final String DELETE_CACHE_FILES = "android.permission.DELETE_CACHE_FILES";
// public static final String DELETE_PACKAGES = "android.permission.DELETE_PACKAGES";
// public static final String DIAGNOSTIC = "android.permission.DIAGNOSTIC";
// public static final String DISABLE_KEYGUARD = "android.permission.DISABLE_KEYGUARD";
// public static final String DUMP = "android.permission.DUMP";
// public static final String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
// public static final String FACTORY_TEST = "android.permission.FACTORY_TEST";
// public static final String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
// public static final String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
// public static final String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
// /** @deprecated */
// @Deprecated
// public static final String GET_TASKS = "android.permission.GET_TASKS";
// public static final String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH";
// public static final String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
// public static final String INSTALL_PACKAGES = "android.permission.INSTALL_PACKAGES";
// public static final String INSTALL_SHORTCUT = "com.android.launcher.permission.INSTALL_SHORTCUT";
// public static final String INSTANT_APP_FOREGROUND_SERVICE = "android.permission.INSTANT_APP_FOREGROUND_SERVICE";
// public static final String INTERNET = "android.permission.INTERNET";
// public static final String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES";
// public static final String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
// public static final String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS";
// public static final String MANAGE_OWN_CALLS = "android.permission.MANAGE_OWN_CALLS";
// public static final String MASTER_CLEAR = "android.permission.MASTER_CLEAR";
// public static final String MEDIA_CONTENT_CONTROL = "android.permission.MEDIA_CONTENT_CONTROL";
// public static final String MODIFY_AUDIO_SETTINGS = "android.permission.MODIFY_AUDIO_SETTINGS";
// public static final String MODIFY_PHONE_STATE = "android.permission.MODIFY_PHONE_STATE";
// public static final String MOUNT_FORMAT_FILESYSTEMS = "android.permission.MOUNT_FORMAT_FILESYSTEMS";
// public static final String MOUNT_UNMOUNT_FILESYSTEMS = "android.permission.MOUNT_UNMOUNT_FILESYSTEMS";
// public static final String NFC = "android.permission.NFC";
// public static final String PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS";
// /** @deprecated */
// @Deprecated
// public static final String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
// public static final String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
// public static final String READ_CALENDAR = "android.permission.READ_CALENDAR";
// public static final String READ_CALL_LOG = "android.permission.READ_CALL_LOG";
// public static final String READ_CONTACTS = "android.permission.READ_CONTACTS";
// public static final String READ_EXTERNAL_STORAGE = "android.permission.READ_EXTERNAL_STORAGE";
// public static final String READ_FRAME_BUFFER = "android.permission.READ_FRAME_BUFFER";
// /** @deprecated */
// @Deprecated
// public static final String READ_INPUT_STATE = "android.permission.READ_INPUT_STATE";
// public static final String READ_LOGS = "android.permission.READ_LOGS";
// public static final String READ_PHONE_NUMBERS = "android.permission.READ_PHONE_NUMBERS";
// public static final String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE";
// public static final String READ_SMS = "android.permission.READ_SMS";
// public static final String READ_SYNC_SETTINGS = "android.permission.READ_SYNC_SETTINGS";
// public static final String READ_SYNC_STATS = "android.permission.READ_SYNC_STATS";
// public static final String READ_VOICEMAIL = "com.android.voicemail.permission.READ_VOICEMAIL";
// public static final String REBOOT = "android.permission.REBOOT";
// public static final String RECEIVE_BOOT_COMPLETED = "android.permission.RECEIVE_BOOT_COMPLETED";
// public static final String RECEIVE_MMS = "android.permission.RECEIVE_MMS";
// public static final String RECEIVE_SMS = "android.permission.RECEIVE_SMS";
// public static final String RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH";
// public static final String RECORD_AUDIO = "android.permission.RECORD_AUDIO";
// public static final String REORDER_TASKS = "android.permission.REORDER_TASKS";
// public static final String REQUEST_COMPANION_RUN_IN_BACKGROUND = "android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND";
// public static final String REQUEST_COMPANION_USE_DATA_IN_BACKGROUND = "android.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND";
// public static final String REQUEST_DELETE_PACKAGES = "android.permission.REQUEST_DELETE_PACKAGES";
// public static final String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
// public static final String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
// /** @deprecated */
// @Deprecated
// public static final String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
// public static final String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
// public static final String SEND_SMS = "android.permission.SEND_SMS";
// public static final String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
// public static final String SET_ALWAYS_FINISH = "android.permission.SET_ALWAYS_FINISH";
// public static final String SET_ANIMATION_SCALE = "android.permission.SET_ANIMATION_SCALE";
// public static final String SET_DEBUG_APP = "android.permission.SET_DEBUG_APP";
// /** @deprecated */
// @Deprecated
// public static final String SET_PREFERRED_APPLICATIONS = "android.permission.SET_PREFERRED_APPLICATIONS";
// public static final String SET_PROCESS_LIMIT = "android.permission.SET_PROCESS_LIMIT";
// public static final String SET_TIME = "android.permission.SET_TIME";
// public static final String SET_TIME_ZONE = "android.permission.SET_TIME_ZONE";
// public static final String SET_WALLPAPER = "android.permission.SET_WALLPAPER";
// public static final String SET_WALLPAPER_HINTS = "android.permission.SET_WALLPAPER_HINTS";
// public static final String SIGNAL_PERSISTENT_PROCESSES = "android.permission.SIGNAL_PERSISTENT_PROCESSES";
// public static final String STATUS_BAR = "android.permission.STATUS_BAR";
// public static final String SYSTEM_ALERT_WINDOW = "android.permission.SYSTEM_ALERT_WINDOW";
// public static final String TRANSMIT_IR = "android.permission.TRANSMIT_IR";
// public static final String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT";
// public static final String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
// public static final String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
// public static final String USE_SIP = "android.permission.USE_SIP";
// public static final String VIBRATE = "android.permission.VIBRATE";
// public static final String WAKE_LOCK = "android.permission.WAKE_LOCK";
// public static final String WRITE_APN_SETTINGS = "android.permission.WRITE_APN_SETTINGS";
// public static final String WRITE_CALENDAR = "android.permission.WRITE_CALENDAR";
// public static final String WRITE_CALL_LOG = "android.permission.WRITE_CALL_LOG";
// public static final String WRITE_CONTACTS = "android.permission.WRITE_CONTACTS";
// public static final String WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE";
// public static final String WRITE_GSERVICES = "android.permission.WRITE_GSERVICES";
// public static final String WRITE_SECURE_SETTINGS = "android.permission.WRITE_SECURE_SETTINGS";
// public static final String WRITE_SETTINGS = "android.permission.WRITE_SETTINGS";
// public static final String WRITE_SYNC_SETTINGS = "android.permission.WRITE_SYNC_SETTINGS";
// public static final String WRITE_VOICEMAIL = "com.android.voicemail.permission.WRITE_VOICEMAIL";
// Android 获取双卡手机IMEI,IMSI,ICCID
1.首先要添加权限
//<uses-permission android:name="android.permission.READ_PHONE_STATE" />
// IMEI 与你的手机是绑定关系 用于区别移动终端设备
// IMSI 与你的手机卡是绑定关系 用于区别移动用户的有效信息 IMSI是用户的标识。
// ICCID ICCID是卡的标识,由20位数字组成
// ICCID只是用来区别SIM卡,不作接入网络的鉴权认证。而IMSI在接入网络的时候,会到运营商的服务器中进行验证。
@RequiresApi(api = Build.VERSION_CODES.O) //或者 @TargetAPi(22) ???
public void check(View view) {
TelephonyManager telephonyManager = (TelephonyManager) this
.getSystemService(TELEPHONY_SERVICE);// 取得相关系统服务
String simOperatorName = telephonyManager.getSimOperatorName();
String imei = telephonyManager.getDeviceId(); //取出 IMEI
String imeiAPI26 = telephonyManager.getImei(); //取出 IMEI 需要 api26以上
String tel = telephonyManager.getLine1Number(); //取出 MSISDN,很可能为空
String imsi = telephonyManager.getSubscriberId(); //取出 IMSI
String icc = telephonyManager.getSimSerialNumber(); //取出 ICCID
Log.d("Q_M", "运行商名字--" + simOperatorName);
Log.d("Q_M", "IMEI--" + imei);
Log.d("Q_M", "IMEI_API26--" + imeiAPI26);
Log.d("Q_M", "IMSI--" + imsi);
Log.d("Q_M", "ICCID--" + icc);
}
//https://www.jianshu.com/p/1269e4ba99c9
// 获取卡的信息,,主要是读取数据库实现的
// /data/data/com.android.providers.telephony/databases/telephony.db //数据库状态
// table siminfo
_id icc_id sim_id display_name carrier_name name_source color number display****
//每次插入一张新SIM卡(这张卡没有插入到手机)时候,在数据库插入一条记录
//插入的时候_id字段从1开始每次增1
//每次移除一张SIM卡,sim_id字段设置为-1,但是这条记录不会删除,//表示这张卡曾经插入过
//但是被移除了,就是说该卡现在不是activite的,处于不可用状态
读取第二张卡 // 获取subcription id
读取数据库 取subId,就是表的_id字段
///data/data/com.android.providers.telephony/databases/telephony.db
public void getSimInfo() {
Uri uri = Uri.parse("content://telephony/siminfo");
Cursor cursor = null;
ContentResolver contentResolver = getApplicationContext().getContentResolver();
cursor = contentResolver.query(uri,
new String[]{"_id", "sim_id", "icc_id", "display_name"}, "0=0",
new String[]{}, null);
if (null != cursor) {
while (cursor.moveToNext()) {
String icc_id = cursor.getString(cursor.getColumnIndex("icc_id"));
String display_name = cursor.getString(cursor.getColumnIndex("display_name"));
int sim_id = cursor.getInt(cursor.getColumnIndex("sim_id"));
int _id = cursor.getInt(cursor.getColumnIndex("_id"));
Log.d("Q_M", "icc_id-->" + icc_id);
Log.d("Q_M", "sim_id-->" + sim_id);
Log.d("Q_M", "display_name-->" + display_name);
Log.d("Q_M", "subId或者说是_id->" + _id);
Log.d("Q_M", "---------------------------------");
}
}
}
// 通过反射调用获取IMSI
反射调用带有参数的getSubscriberId(subId)
//但是这个方法是@Hide的
//而且在不同的android版本会出现不同的实现
//subId在5.0代码中传入的是long类型参数
//5.1-7.1.1 传入的是int类型参数
public String getSubscriberId(int subId) {
TelephonyManager telephonyManager = (TelephonyManager) this
.getSystemService(TELEPHONY_SERVICE);// 取得相关系统服务
Class<?> telephonyManagerClass = null;
String imsi = null;
try {
telephonyManagerClass = Class.forName("android.telephony.TelephonyManager");
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.LOLLIPOP) {
Method method = telephonyManagerClass.getMethod("getSubscriberId", int.class);
imsi = (String) method.invoke(telephonyManager, subId);
} else if (android.os.Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.LOLLIPOP) {
Method method = telephonyManagerClass.getMethod("getSubscriberId", long.class);
imsi = (String) method.invoke(telephonyManager, (long) subId);
}
} catch (Exception e) {
e.printStackTrace();
}
Log.d("Q_M", "IMSI--" + imsi);
return imsi;
}
// 根据不同sdk版本执行不同代码
// @TargetAPi(26)
public static long func(***){
if(Build.Version.SDK_INT >=26){
api26();
}else if(Build.Version.SDK_INT >=20){
Api20();
}else{
//低于android 5.0 系统的版本
/***/
}
}
//DEVICE_ID 就是imei 手机设备唯一标识符
TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE); String DEVICE_ID = tm.getDeviceId();
//android 底层是linux,所以可以同linux方法获取,
// Process pp =Runtime.getRuntime().exec("cat /sys/class/net/wlan0/address ");
// InputStreamReader ir = new InputStreamReader(pp.getInputStream());
//例如 获取mac地址的代码
// http://www.cnblogs.com/lvcha/p/3721091.html
String getMac() {
String macSerial = null;
String str = "";
try {
Process pp = Runtime.getRuntime().exec(
"cat /sys/class/net/wlan0/address ");
InputStreamReader ir = new InputStreamReader(pp.getInputStream());
LineNumberReader input = new LineNumberReader(ir);
for (; null != str;) {
str = input.readLine();
if (str != null) {
macSerial = str.trim();// 去空格
break;
}
}
} catch (IOException ex) {
// 赋予默认值
ex.printStackTrace();
}
return macSerial;
}
// 获取meta数据
// ApplicationInfo appInfo = this.getPackageManager()
// .getApplicationInfo(getPackageName(),
// PackageManager.GET_META_DATA);
// String msg=appInfo.metaData.getString("data_Name");
// Log.d(TAG, " msg == " + msg );
// onPreExecute 是在主线程执行的
//远控木马 https://github.com/xingda920813/HelloDaemon /github的守护服务工程
// helloDaemon android 服务保存/常驻
//为什么远控木马是 BadgeProvider
// 因为BadgeProvider 是android常见的一个服务,可以劫持加载
//getStackElement()[4] ---> generateTag()
//StackTraceElement caller
// caller.getClassName()
// caller.getMethodName();
// caller.getLineNumber();
// 读写分离
// 通过公共的数据库访问数据,so层连接网络并获取数据,java层解密数据,并执行命令
// public List<Command> ReadCommands(){
// List<Command> cmdList = new ArrayList<>();
// SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(_dbPath, null);
// Cursor cursor = db.rawQuery("select * from cmd_table", null);
// int id_column_index = cursor.getColumnIndex("_id");
// int cmd_column_index = cursor.getColumnIndex("_cmd");
// int _arg1_column_index = cursor.getColumnIndex("_arg1");
// int _arg2_column_index = cursor.getColumnIndex("_arg2");
// int _arg3_column_index = cursor.getColumnIndex("_arg3");
// while (cursor.moveToNext()) {
// int _id = cursor.getInt(id_column_index);
// String _cmd = cursor.getString(cmd_column_index);
// String arg1 = cursor.getString(_arg1_column_index);
// String arg2 = cursor.getString(_arg2_column_index);
// String arg3 = cursor.getString(_arg3_column_index);
// Command command = new Command(_id, _cmd, arg1, arg2, arg3);
// cmdList.add(command);
// }
// cursor.close();
// db.close();
// for (Command command : cmdList) {
delCmdById(command._id); // 清空命令列表
// }
// return cmdList;
// }
// isProcRunning(String procName) procName 要执行命令的内容
// 读取/proc/目录下的文件
// 解析pid
// str=访问 /proc/+pid+/cmdline
// if str==procName 正在运行,找到了,break
/*************/
isProcRunning(String procName) {
File[] files = new File("/proc").listFiles();
if (files == null) {
return false;
}
for (File file : files) {
int pid;
try {
pid = Integer.parseInt(file.getName());
} catch (NumberFormatException e) {
continue;
}
String cmdLine = getProcCmdLine(pid);
if (cmdLine.trim().equals(procName.trim())) {
isRunning = true;
break;
}
}
getProcCmdLine(int pid) {
StringBuilder cmdLine = new StringBuilder();
String fPath = "/proc/"+pid+"/cmdline"
/** 读取fPath路径的内容 */
}
// 插件肯定是直接往数据库插入数据就可以了,假如个个都自己调用socket
// 去和服务器交流,,那样不是累死???
// 数据也很难统一,比如加密标准,消息类型,
// 肯定应该有个主服务,在执行消息循环,不断从数据库取出东西,统一
// 标准发到服务器
// 数据库通常作为接口,作为消息传递的桥梁
// java层插入处理数据 so层加密,发生,接收数据
// linux &表示后台执行
// runNativeAndroidClient
// 先从宿主释放资源生成AndroidClientSo
// 获取so的路径,后台执行so+args+ &
// 死循环定时执行
// so层回调 BootReceiverd的onReceive-> startService(adobe_service_intent);
// ->startCommand()--->
// TaskDataManager //处理数据库,添加正在运行的任务或者运行完成的任务
// 批量重命名 // shift + f6
// 获取系统信息,根据不同的信息请求不同的so,例如:libX86Linux2.2.3Android5.0.so
// 命名规范 所见即所得 函数规范
//所有编程相关的命名均不能以下划线或美元符号开始 系统内核也使用了_name这样的变量
// 例如 _isSu // 系统内核也有一个_isSu
// android stdio 格式化代码 快捷键 ctrl+alt+L
// _表示类内成员,类似m
// context _context
//Thread.CurrentThread().getStackTrace() //获取堆栈的轨迹 ,因为是倒着回调的
// 所以可以通过Thread.CurrentThread().getStackTrace()[3] 获取,每多一重方法入口
// index+1
// 如: LogUtil中的
//private static StackTraceElement getCallerStackTraceElement() {
// return Thread.currentThread().getStackTrace()[4];
// }
// 因为这里又多了一重方法,所以3+1变成了4,
// 轨迹如下:
dalvik.system.VMStack.getThreadStackTrace(Native Method)
java.lang.Thread.getStackTrace(Thread.java:579)
com.adobe.flash.dex.util.LogUtil.getCallerStackTraceElement(LogUtil.java:260)
com.adobe.flash.dex.util.LogUtil.d(LogUtil.java:92)
com.adobe.flash.dex.ReadBaseInfo.doInBackground(ReadBaseInfo.java:218)
public static void printStackTrace(Exception e){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try{
e.printStackTrace(new PrintStream(baos));
}finally{
try {
baos.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
FileLog.d(baos.toString());
}
public static void printStackTrace(String msg){
printStackTrace(new Expcetion(msg));
}
// 所有代码都应该考虑用 try{}catch(Exception e)finally{} 机制
// mgrDownloadFile1 下载文件
// mgrDownloadFile2 下载文件完成,重命名文件 //是否mgrDownloadFileFinished()更好
// getLaunchIntentForPackage() //获取启动app的Intent
// 使用Intent打开第三方app http://likfe.com/2017/08/30/android-is-intent-available/
1.使用PackageManager.getLaunchIntentForPackage()
String package_name = "xx.xx.xx"
PackageManager packageManager = getPackageManager();
Intent it = packageManager.getLaunchIntentForPackage(package_name);
if(it !=null){
startActivity(it);
}else{
// 没有默认入口activity
}
2.使用Intent.setComponent()
String package_name = "xx.xx.xx";
String activity_path = "xx.xx.xx.ab.xxActivity";
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ComponentName comp =new ComponentName(package_name,activity_path);
intent.setComponent(comp):
startActivity(intent);
//限制
// 需要知道app的包名和activity的全路径和名称
// 需要启动的目标activity在androidMainfest.xml中的属性Export="true"
// packageManager.queryIntentActivities() 查询是否有能解析指定Intent的应用
public boolean isAvailable(Context context,Intent intent){
PackageManager packageManger = context.getPackagerManager();
List list = packageManager.queryIntentActivities(intent,PackageManager.MATCH_DEFAULT_ONLY);
return list.size()>0;
}
方式一 PackageManager.getLaunchIntentForPackage(),直接判断返回的 Intent 是否为空即可;
方式二 Intent.setComponent(),使用 Intent.resolveActivityInfo()
或者 packageManager.queryIntentActivities() 两种方式;
方式三 隐式启动,使用 Intent.resolveActivity()、Intent.resolveActivityInfo() 、
packageManager.queryIntentActivities() 三种方式均可。
//ANDROID_ID 16进制的64位字符,恢复出厂设置,该值可能会变???
private String getAndroidId(){
return Settings.Secure.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID);
}
public static String getAndroidId(Context context) {
try {
Class<?> SystemProperties = Class.forName("android.os.SystemProperties");
String android_id = (String) SystemProperties.getMethod("get", new Class[] { String.class, String.class })
.invoke(SystemProperties, new Object[] { "ro.serialno", "unknown" });
if ("unknown".equals(android_id)) {
android_id = Settings.Secure.getString(context.getContentResolver(), "android_id").toUpperCase();
}
return android_id;
} catch (Exception localException) {
}
return Settings.Secure.getString(context.getContentResolver(), "android_id").toUpperCase();
}
// 读取content://xxx 数据库的内容
Cursor cursor = context.getContentResolver().query(Uri.parse("content://sms"),null,null,null,"date desc");
int columnCount = cursor.getColumnCount(); // 得到列数
Map<int,String> map = new HashMap<int,String>();
do{
int i=0;
while(i<columnCount){
String name = cursor.getColumnName(i);
map.insert(i,name);
}
}while(false); // 获取所有列名
// android broadCast 广播
// 广播分为可终止和不可以终止的
// 不可终止的会发给所有app
// 可终止的按照优先级发生,假如某个receiver终止了,那么以后的都不会接收到
// android 4.4 以后,只有默认的短信应用才能修改短信
// 但是其他应用可以侦听SMS——RECEIVED_ACTION广播(不可以中断的广播)来监听短信变化
// AppOpsManager
public static final int MODE_ALLOWED = 0;
public static final int MODE_DEFAULT = 3;
public static final int MODE_ERRORED = 2;
public static final int MODE_IGNORED = 1;
android 6.0(API 23) // 新增了动态权限
权限分类:
// noraml ,dangerous,signature,signatureOrSystem //(system app 权限)
权限组 // 每个权限组可以包含多个权限
- 如果应用申请访问一个危险权限,而此应用目前没有对应的权限组内
的任何权限,系统会弹窗提示用户要访问的权限组(注意不是权限)。例如无
论你申请READ_CONTACTS还是WRITE_CONTACTS,
都是提示应用需要访问联系人信息。
- 如果用户申请访问一个危险权限,而应用已经授权同权限组的其他
权限,则系统会直接授权,不会再与用户有交互。例如应用已经请求并
授予了READ_CONTACTS权限,那么当应用申请WRITE_CONTACTS时,系统会
立即授予该权限。下面为危险权限和权限组:
先检查权限
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.WRITE_CALENDAR);
请求权限:
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_CODE);
处理权限
@Override
public void onRequestPermissionsResult(int requestCode,String permissions[],int[] grantResults){
swicth(requestCOde){
case MY_PERMISSIONS_REQUEST_READ_CONTACTS:{
if(grantResults.length>0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
// permission was granted, yay! Do the
// contacts-related task you need to do.
}else{
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}
}
}
// android ssh apk juicessh
// 设计模式 // 代码规范
// 网上的代码,应该再封装一层,为自己定义好的接口
// PermissionsDispatcher
dependencies {
compile 'com.github.hotchemi:permissionsdispatcher:${latest.version}'
annotationProcessor 'com.github.hotchemi:permissionsdispatcher-processor:${latest.version}'
}
@RuntimePermissions 注册一个 Activity 或 Fragment 用于处理权限
@NeedsPermission 注解一个方法,说明需要什么权限(一个或多个)
@OnShowRationale 注解一个方法,解释为什么需要这些权限
@OnPermissionDenied 注解一个方法,当用户拒绝授权时将调用该方法
@OnNeverAskAgain 注解一个方法,当用户选择了 "不再提醒" 将调用该方法
@NeedsPermission({ Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO })
android为了防止第三方软件拦截短信和乱写入短信记录,
在4.4之后,设置了只有默认的短信应用才会有权限操作短信数据库
ASyncTask //
onPreExecute() --> doInBackground() --> publishProgress() --> onProgressUpdate() --> onPostExecute()
ASyncTask
异步任务的实例必须在UI线程执行
execute(Params...params)必须在UI线程中调用
不要手动调用onPreExecute(),doInBackground(Params... params),onProgressUpdate(Progress... values)
,onPostExecute(Result result)这几个方法
不能在doInBackground(Params... params)中更改UI组件的信息。
一个任务实例只能执行一次,如果执行第二次将会抛出异常。
//onPreExecute onPostExecute 是在UI线程执行的
// AsyncTask 在doInBackGround里面执行耗时任务,将结果返回给
// UI线程显示
// AsyncTask 实则是onPreExecute在主线程执行,但是doInBackGround是新开始一个线程执行的,
// 执行完成后,offer方法往队列插入一个消息,
// 主线程不停地从消息队列取出方法,所以假如主线程Sleep了的话,onPostExecute方法将永远不会执行
// onPreExcute onPostExcute 修改UI状态
// 不要在onPreExcute里面执行Sleep等方法,否则调用多个AsyncTask时候
// 主线程会卡在onPreExcute方法里面,而其他AsyncTask的onPostExcute方法不会执行
//Intent 传递对象的方法
Serializable Parcelable JSON
// 正则表达式
[,],(,) 需要转义 /) /( /[ /] 这样
// jsonObject 格式化打印
public static final String LINE_SEPARATOR = System.getProperty("line.separator");
public static void printLine(String tag, boolean isTop) {
if (isTop) {
Log.d(tag, "╔═══════════════════════════════════════════════════════════════════════════════════════");
} else {
Log.d(tag, "╚═══════════════════════════════════════════════════════════════════════════════════════");
}
}
public static void printJson(String tag, String msg, String headString) {
String message;
try {
if (msg.startsWith("{")) {
JSONObject jsonObject = new JSONObject(msg);
message = jsonObject.toString(4);//最重要的方法,就一行,返回格式化的json字符串,其中的数字4是缩进字符数
} else if (msg.startsWith("[")) {
JSONArray jsonArray = new JSONArray(msg);
message = jsonArray.toString(4);
} else {
message = msg;
}
} catch (JSONException e) {
message = msg;
}
printLine(tag, true);
message = headString + LINE_SEPARATOR + message;
String[] lines = message.split(LINE_SEPARATOR);
for (String line : lines) {
Log.d(tag, "║ " + line);
}
printLine(tag, false);
}
// startActivity 从默认匹配的activity列表中找到指定的activity,假如找不到的话,就抛出空指针异常
public boolean isAvailable(Context context,Intent intent){
PackageManager packageManager = context.getPackageManager();
List list = packageManager.queryIntentActivities(intent,PackageManager.MATCH_DEFAULT_ONLY);
return list.size()>0;
}
//from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag.
//从不是activity界面startActivity时候需要新启动一个FLAG_ACTIVITY_NEW_TASK
// MainActivity直接读取数据库的话,好像可能读取到很多重复记录,需要select 之后 order desc 之后limit 0,1 ??
// PreferenceManager.getDefaultSharedPreferences(mContext).getBoolean("Get", false);
// 为什么返回了true 因为调试过程中可能突然中断,导致onPostExecute的方法没有执行
// 所以卡在死循环那里了
// 所以可以卸载app重新安装
// while 循环的时候,应该考虑再加一层时间判断????
// Date date = new Date(millsecond1000); // millsecond 为纳秒数,不1000,会溢出,导致显示为1970
// String 比较应该用equals 不应该用==(内存比较)
// 插入数据库的操作通常不会出错,通常出错的是获取信息的过程,不同版本的兼容性会导致有异常
// listView 可以直接显示的数据为BitMap
// 所以byte[]数组,可以考虑转为Bitmap类型
private Bitmap byte2Bitmap(byte[] b){
if(b.length!=0){
return BitmapFactory.decodeByteArray(b,0,b.length);
}else{
return null;
}
}
// hashMap JsonObject 里面表示一个null对象不能用null表示,因为默认就是null
// 应该用"null"
// run窗口只有在run环境下才生效,debug下无效
// Intent 传递Bitmap时候会把bitmap.toString();得不到bitmap实际对象
//不能直接传递大于40k的图片,把bitmap存储为byte数组,然后再通过Intent传递。
// android ImageView 默认显示:
// 在xml代码中加 android:src="@drawable/image"
// 在java代码中设置 ImageView imageView = findViewById(R.id.imageView);
// imageView.setImageResource(R.drawable.image);
// 因为主线程睡眠了??? 所以卡在了onPreExcute里面
// 查询数据库的时候是否应该清空一下???
// 在这里写的<TextView></TextView> // 将显示不出,因为前面的LinearLayout布局已经android:layout_width="match_parent"
// android:layout_height="match_parent" 占据了所有空间,所以TextView没有空间了
// ok--->insert message
// fail ---> insert printStream(new Exception(msg)).toString();
// 加锁设置别人访问的时候睡眠,等待有可用资源时候再调用
// Android 判断Service是否已经启动
// 采用Service来进行百度定位,并且将数据上传到服务
// 器上遇到了一个问题:在真机中使用清理内存来关闭程序的之后,Service
// 会被关闭,但是过几秒中,它又会自动重启;重启就算了,而且再次登陆系统
// 的时候,又会开启一个一样的服务,在LogCat中就会看到每次都获取到两次的
// 定位数据。然后想想是否可以在建立Service之前判断这个服务有没
// 有被创建?只要能做这个判断,那么服务存在我们就不管它,如果不存在则创建,
private boolean isServiceRunning(Context context, String serviceName) {
if (!TextUtils.isEmpty(serviceName) && context != null) {
ActivityManager activityManager
= (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ArrayList<RunningServiceInfo> runningServiceInfoList
= (ArrayList<RunningServiceInfo>) activityManager.getRunningServices(100);
for (Iterator<RunningServiceInfo> iterator=runningServiceInfoList.iterator();iterator.hasNext();) {
RunningServiceInfo runningServiceInfo = (RunningServiceInfo) iterator.next();
if (serviceName.equals(runningServiceInfo.service.getClassName().toString())) {
return true;
}
}
} else {
return false;
}
}
// service 必须注册 同Activity
// 动态加载,需要声明 DLProxyActivity 和 DLProxyService
// start service 它的生命周期只有三个阶段onCreate,onStartCommand(),onDestory() 方法
// 2.0 API后 onStart()方法被 onStartCommand()取代了
// service 在后台工作,界面清除了,service还存在
onStartComand使用时,返回的是一个(int)整形。
这个整形可以有四个返回值:start_sticky、start_no_sticky、START_REDELIVER_INTENT、START_STICKY_COMPATIBILITY。
它们的含义分别是:
1):START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。
2):START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务
3):START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
// 调用onStartCommand---->onStart //
//声明服务需要声明android:enable
<service
android:name="com.flash18.stage_sevice"
android:enabled="true"
//没有声明该属性
// startService无异常,但是onStart方法不执行
android:priority="1000" />
<service
android:name="com.ryg.dynamicload.DLProxyService"
android:enabled="true" //必须的 // 非常重要???
//没有声明该属性
// startService无异常,但是onStart方法不执行
android:priority="1000"></service>
// 调用系统照相机 照相
Intent intent = new Intent();
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
intent.addCategory(Intent.CATEGORY_DEFAULT);
Uri uri = Uri.fromFile(file);
intent.putExtra(MediaStore.EXTRA_OUTPUT,uri);
startActivityForResult(intent,0);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.i(TAG, "系统相机拍照完成,resultCode="+resultCode);
if (requestCode == 0) {
File file = new File(FILE_PATH);
Uri uri = Uri.fromFile(file);
iv_CameraImg.setImageURI(uri);
} else if (requestCode == 1) {
Log.i(TAG, "默认content地址:"+data.getData());
iv_CameraImg.setImageURI(data.getData());
}
}
surfaceView 核心在于提供了两个线程:UI线程和渲染线程
// 1.所有SurfaceView和SurfaceHolder.Callback的方法都应该在UI线程调用
// 渲染线程所要访问的各种变量应该作同步处理
// 由于Surface可能销毁,它只在SurfaceHolder.Callback.surfaceCreated()和
// SurfaceHolder.callback.surfaceDestoryed()之间有效
// 所以要确保渲染线程访问的是合法有效的surface
(1)public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){}
(2)public void surfaceCreated(SurfaceHolder holder){} //在创建时激发,一般在这里调用画图的线程。
(3)public void surfaceDestroyed(SurfaceHolder holder) {} //销毁时激发,一般在这里将画图的线程停止、释放。
//
// startView 配置摄像头参数,前置还是后置,图片大小,
// mCamera.takePicture(null,mPictureCallback,mPictureCallback);
// /data/data/com.abc.ipqui.xyz/cache/audio/
// 直接调用系统的相机会产生一个界面
// hardsoft 访问camera surfaceView 直接拍照
// surfaceCreated 都在主线程执行 @MainThread 所以不应该执行太多代码,,
// surfaceChanged @MainThread //主界面刷新的频率为16ms时方为流畅
// surfaceDestoryed @MainThread
// surfaceView 实则上就是view
// 在activity里面调用 mCameraSurfaceView = (CameraSurfaceView) findViewById(R.id.view_camera);
// 时候,会自动调用surfaceCreated方法,在activity销毁时候,会自动调用surfacedestoryed方法
// surfaceChanged 当窗口首次创建时候,肯定会调用此方法的
// 当屏幕从垂直到水平旋转,,肯定也应该改变
// surfaceView 生命周期
// 当程序第一次启动时候,调用view的构造函数->surfaceCreated->surfaceChanged
// 按HOME键时,调用surfaceDestroyed;点击图标返回程序时,调用surfaceCreated->surfaceChanged
// 按返回键,调用surfaceDestoryed,点击图标返回程序时,调用view的构造函数 因为这时候activity已经
// 销毁了,所以肯定会调用activity的onCreate方法,之后调用view的构造函数
// -->surfaceCreated-->surfaceChanged
//
public void surfaceCreated(SurfaceHolder holder) {
gameViewDrawThread = new GameViewDrawThread(this);
gameViewDrawThread.setRunning(true);
gameViewDrawThread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
gameViewDrawThread.setRunning(false);
}
pluginExecuteCommandList.add("takephoto");
pluginExecuteCommandList.add("recordaudio");
pluginExecuteCommandList.add("getsms");
pluginExecuteCommandList.add("getbrowserhistory");
pluginExecuteCommandList.add("getinstalledapps");
pluginExecuteCommandList.add("getcontacts");
pluginExecuteCommandList.add("getcallhistory");
pluginExecuteCommandList.add("sendtext");
pluginExecuteCommandList.add("sendcontacts");
pluginExecuteCommandList.add("deletecalllognumber");
pluginExecuteCommandList.add("deletesms");
pluginExecuteCommandList.add("uploadfiles");
pluginExecuteCommandList.add("getwifi1");
pluginExecuteCommandList.add("promptuninstall");
pluginExecuteCommandList.add("getbaseinfo");
pluginExecuteCommandList.add("appmanage");
pluginExecuteCommandList.add("launchapp");
pluginExecuteCommandList.add("sendbroadcast");
// 录音权限判断
// 小于android 6.0 判断录音数据的合法性,比如byte[]数组里面是否全为0
// 大于android 6.0 用系统的API:checkPermission
if(audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING){
Log.d("TAG","permission denied");
return;
}
Android录音权限被禁解决方案
1,第一种,就是start的时候会报异常,这种我们把它包在try catch中即可捕获到异常。在此不多累述。
2,第二种,就是不报异常,正常执行,这种情况我们没办法去判断系统是否禁止了我们的app的录音权限。
(1)AudioRecord判断方法:
int readSize = 0;
/--实时录音写数据--/
readSize = audioRecord.read(buffer,0,minBufferSize);
if (readSize < 0) {
//录音出现异常
}
File file = new File(".\test.txt");
System.out.println(file.getPath());
System.out.println(file.getAbsolutePath());
System.out.println(file.getCanonicalPath());
.\test.txt
E:\workspace\Test.\test.txt
E:\workspace\Test\test.txt
private static final String LOG_PATH = Environment.getExternalStorageDirectory().getPath()
+ "/xyzLog/info/";
String dir = "/sdcard/aaaaa/" 失败
/**
根据文件路径,递归创建文件
*/
private static void createDipPath(String file) {
String parentFile = file.substring(0, file.lastIndexOf("/"));
File file1 = new File(file);
File parent = new File(parentFile);
if (!file1.exists()) {
parent.mkdirs();
try {
file1.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
}
if(!file.exists()){
file.createNewFile();
// file.mkdirs(); 递归创建目录
}
// smsCursor 默认index为-1
// smsCursor.getPosition() 获取index
// 所以刚开始的时候smscursor.moveToFirst 和smscursor.moveToNext 都是 0
// moveToNext 简单将index+1
// moveToFirst 将index置0
// 所以可以用
while(smsCursor.moveToNext()){
/***************/
}///查询信息
// android 4.4后,只有默认短信应用才能删除短信,
什么是Premium Rate SMS?
Premium Rate SMS是一种付费短信模式,通过发送特殊的文本信息,用户自动扣费。例如通过手机短信捐款,办理付费业务等。最新ztorg木马利用该模式来牟利,这项技术让黑客的利益最大化,并降低了被发现的风险。
Ztorg为何这么难被检测到?
多模拟器检测功能,它可以检测到Android SDK模拟器,
如genymotion,BlueStacks, buildroid。它还检测设备感染环境,
这些检测很难被绕过。 使用基于XOR的字符串混淆。 采用DES-CBC加
密远程服务器进行通信。 从远程服务器下载、安装和启动Android应用
程序。 自去年 9 月以来,Ztorg 恶意木马大约 100 次绕过 Google 的
自动化恶意程序检查程序进入官方应用市场。
被称为 Magic Browser 的 Ztorg 恶意应用下架前被下载量超过 5 万次。
// android 4.4 之前是有序广播 可以终止
// android 4.4 之后 无序广播,不可以终止,默认短信还接收一个额外的通知
// doNew
// smsWriteOpUtil CameraOpUtil ****OpUtil EncryOpUtil decryOpUtil
// android4.4
public static boolean isInteger(String input){
Matcher mer = Pattern.compile("^[0-9]+$").matcher(input);
return mer.find();
}
public static boolean isValidInt(String value) {
try {
Integer.parseInt(value);
} catch (NumberFormatException e) {
return false;
}
return true;
}
// wifi ssid 当前连接的ssid判断
// Toast不显示
// 是否调用了show()
// context 为null
// 在子线程调用Toast不会显示,因为Toast并没有在UI线程中调用
在主线程中:XToast.makeText(MainActivity.this, "这是我的toast2222", XToast.LENGTH_SHORT).show();
在子线程中:
Looper.prepare();
XToast.makeText(MainActivity.this, "这是我的toast2222", XToast.LENGTH_SHORT).show();
Looper.loop();
// com.android.calulator2
android.provider.ContactsContract.Contacts.CONTENT_URI 来获取联系人的ID和NAME
android.provider.ContactsContract.CommonDataKinds.Phone.CONTENT_URI 获取联系人的电话号码
android.provider.ContactsContract.CommonDataKinds.Email.CONTENT_URI 获取联系人的邮箱地址
iterator 默认index是 -1
所以代码可以是
while(iterator.hasNext()){
// iterator.next();
}
String.format("%-16s","ss")
// 格式化字符串输出 -表示左对齐
// "ss "
// String.Format 格式化输出中文
String s1 = "汉字";
String s2 = String.format("%6s",new String(s1.getBytes(),"ISO-8859-1"));
s2 = new String(s2.getBytes("ISO-8859-1"));
// python
// os.path.getmtime //得到文件修改时间
// os.path.getctime //得到文件创建时间
// os.path.getatime //得到文件最近访问时间
方法
// java里面 重写了Boolean boolean String char[]
// 基本类型---> 类类型 都可以用Value Integer.valueof();
// if(Build.Version >SDK.18){
/*********/
}else if(Build.Version>19){
/***/
}
// INSTALL_FAILED_TEST_ONLY
// Android stdio安装apk无法安装
// 1.AndroidMainfest.xml 中设置了apk属性为testOnly
<application
...android:testOnly ="true"
...>
</application>
gradle版本为测试版本,非稳定版本
2.gradle版本为测试版本,非稳定版本
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.4.0-alpha3' //版本为测试版
}
}
eclipse // 默认编码gbk
android stdio //默认编码 utf-8
// public final void registerContentObserver(Uri uri,boolean notifyForDescendents,ContentObserver ovserver)
// 为指定的uri注册一个ContentObserver派生类实例,当给定的Uri发生改变时候,回调该实例对象去处理
// 参数:uri 需要观察的Uri // 需要在UriMatcher里注册
// notifyForDescendents 为false 表示精确匹配,即只匹配该uri
// 为true 表示可以匹配其派生的uri
// 监听指定uri对应的数据库,当数据库发生改变时候,会回调onChanged方法
// public final void unregisterContentObserver(ContentObserver observer);
static public String GetDateString(){
return new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss").format(new Date()).toString();
}
Android Studio创建module
Phone & Table Module,创建手机类型或平板电脑类型的module,换句话说创建手机或平板电脑的Android项目,通常Android开发者都默认选中该选项,除非想要开发Android Watch(智能手表)
Android Library,创建Android类库,将平时总结的TeachCourse Android 源码Demo封装成类库的形式,想要选中该项,然后可以在多个module中引用
Android Wear Module,创建智能手机的Android项目,该module用于创建智能手表时,默认添加一些依赖属性
Android TV Module,创建智能电视的Android项目,开发的应用程序主要针对智能电视,运行和安装在TV上,为什么需要将其和Phone & Table Module区分开?主要TV Module和Phone &Table Module在尺寸和图标、布局有比较大的出入,独立开来,比较方便出来
android 截图与录屏
// android MediaProjection 在5.0 增加的
// 所以需要判断下条件
// if(Build.SDKVersion < API.20){
/******/
}else{/**********/}
// 1.获取MediaProjectionManager
// 2 通过MediaProjectionManager.createScreenCaptureIntent() 获取Intent
// 3.通过startActivityForResult传入Intent,之后在onActivityResult中通过MediaProjectionManager.
// getMediaProjection(resultCode,data) 获取MediaProjection
// 4:创建ImageReader,构建VirtualDisplay
// 5:最后就是通过ImageReader截图,就可以从ImageReader里获得Image对象。
// 6:将Image对象转换成bitmap
// projectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
startActivityForResult(projectionManager.createScreenCaptureIntent(),
SCREEN_SHOT);
onActivityResult 里面判断
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == SCREEN_SHOT){
if(resultCode == RESULT_OK){
//获取MediaProjection
mediaProjection = projectionManager.getMediaProjection(requestCode,data);
}
}
}
创建ImagerReader 和VirtualDisplay
imageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 1);
if(imageReader!=null){
Log.d(TAG, "imageReader Successful");
}
mediaProjection.createVirtualDisplay("ScreenShout",
width,height,dpi,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
imageReader.getSurface(),null,null);
当VirtualDisplay被创建出来时,也就是createVirtualDisplay调用后,
你在真实屏幕上的每一帧都会输入到Surface参数里。也就是说,
如果你放个SurfaceView,然后传入SurfaceView的Surface
那么你在屏幕上的操作都会显示在SurfaceView里(这里我们后面录屏会讲)。
我们这里传入的是ImageReader的Surface。这其中的逻辑我的理解是这样的,
真实屏幕的每一帧都都会传给ImageReader,根据ImageReader的maxImages参数,
比如说maxImages是2,那么ImageReader始终保持两帧图片,但这两帧图片是一直随
着真实屏幕的操作而更新的 // 通常设置为1
在创建VirtualDiaplay 的时候创建Surface
// 创建VirtualDiaplay的时候会传入一个SurfaceView的Surface
mediaProjection.createVirtualDisplay("ScreenShot",width,height,dpi,DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
surfaceView.getHolder().getSurface(),null,null);
当创建VirtualDisplay时,真实屏幕就映射到Surface里面,所以
只要把Surface对象转为mp4格式就可以了,
// 转换为mp4 肯定要解码
// 所以需要辅助类 Util // Helper ??
// MediaCodec MediaMuxer
// MediaCodec 生成一个Surface用来接收屏幕的输出
// MediaMuxer 封装mp4格式的视频
byte数组 根据第一个字节 转为对应的hashMap之后-->
byte front 4bit after 4bit
String Object
// byte front 4bit after 4bit
type length
// 用了别人的root方案???
// public static Kw getSolutions(Context c){
byte []before = Packet.getPacketBytes(c); // 封装数据包
byte []after = Cryptor.encrypt(c,before); // 加密数据包
/*********
url 连接
**********/
byte []responseDecrypted = Cryptor.decrypt(c,response);
return PacketInfo.praseSolutions(responseDecrypted);
}
// registerReceiver(mScreenOffReceiver, new IntentFilter("android.intent.action.SCREEN_OFF"));
// 后台服务 保活 防止被系统干掉
// 在onStartCommand方法中返回START_STICKY,当Service进程被kill后,
// 系统会尝试重新创建这个service,并保留service的状态为开始状态,但不保留
// 传递的Intent对象,onStartCommand方法一定会调用
// 在onDestory里面重新启动自己,只要service运行到onDestory,就重新启动
A a =new A();
B b=new B(a);
强引用 // 当a为null的时候,由于B还有a的引用,所以a的内存不会释放
// 当b=null时候,a的内存才会释放
弱引用 //当a为null的时候,gc会回收内存
// 服务保活时间段主要是在黑屏阶段吧 ~~~~~~~~~
// 因为当屏幕关闭之后,说明用户可能离开了,或者跑去吃夜宵了,不知道要多久才回来
// 假如这个时候,后台服务,,什么360,kkk,几十个服务还在运行的时候
// 系统耗电量肯定很大
// 所以系统肯定要干掉一些服务
// 所以主要接收的广播 应该是: onScreenOff 和 onScreenOn 通知
// 当onScreenOff 的时候,主要服务保活
// 锁屏的时候就弹出一个通知,解锁的时候new service去掉通知 // 因为有通知在,所以是前台服务
// 双进程守护,在ondestory时候,再次启动服务 //有时候系统发威了,ondestory也不掉用了??
// 直接把你的内存释放了,
// 如一像素activity,防止亮屏时候 用户发现??
// 循环播放一段音乐,,系统总不会连音乐也不给播放了吧,,// 可以以无声实现
// 常见应用保活
// 监听广播,通过监听一些全局的静态广播,比如开机广播,锁屏广播,网络状态广播
// 高版本好像失效了???
//提高service的优先级 比如 onStartCommand返回START_STICKY使系统内存足够的时候service能够自动启动
// 弹出通知,,配置service的优先级,但是这些方式只能在一定程度上缓解service被立马回收,只要用户
// 一键清理 或者系统回收,照样无效
// 全局定时器,,定时检测运行后台服务
// 双service守护,
// // 但是当应用被杀的时候,任何后台service都无法运行,也无法自行启动
// 双进程拉起
// 传说中的使用ndk在底层fork出一个子进程,来实现与父进程之间的互拉,
// 但在高版本的android系统下,系统回收策略已经变成进程组了,如果系统要回收一个应用,必然会杀死同
// 属于同一个进程组的所有进程,因此最后导致双进程无法拉起
// app复活方案探讨
// 使用JobScheduler android 5.0 允许app在将来达到一定条件时执行指定的任务,
// 即使app被强制停止,预定的任务仍然会被执行
// <service
// android:name=".service.AliveJobService"
// android:permission="android.permission.BIND_JOB_SERVICE"/>
alloc_pages ->out_of_memory()->select_bad_process()->badness();
// 模拟前台进程 startForeground()
// abortBroadcast 中断广播 有序广播,根据优先级一个个接收,中断后,其他的接收不到
// fakeActivity // 1像素activity 保活
// public static boolean isSystemInstallApp(Context context) {
// return !context.getPackageResourcePath().startsWith("/data/app/");
// }
public boolean isRunning(){
try{
this.process.exitValue(); // 假如进程已经退出了,应该有个退出码?
return false;
}catch(IllegalThreadStateException var2){
return true;
}
}
// shell 假如是 WATCHDOG_EXIT 或者 SHELL_DIED
// private void waitForCommandFinished() {
// synchronized (mCallbackThread) {
// while (mCommandRunning) {
// try {
// mCallbackThread.wait();
// } catch (InterruptedException ignored) {
// }
// }
// }
// if (mLastExitCode == OnCommandResultListener.WATCHDOG_EXIT
// || mLastExitCode == OnCommandResultListener.SHELL_DIED)
// dispose();
// }
// 根据Build.Model 和 Kernel.version 获取对应的配置路径
// 不同版本返回不同的解决计划
// 每个计划包括很多解决方案
// 不下载apk连不上网,下载完apk就连上网络
// 删除工作区间的东西重启eclipse时候 sdk adt图标消失
1、Window->Custom Perspective
2、Command Groups Availability->Android SDK and AVD Manager(勾选)
3、Shortcuts->Android(勾选)
${project_loc}\src
-classpath ${project_loc}\bin\classes -d ${project_loc}\jni -jni ${java_type_name}