2018-01-15

//gradle 下載慢 //可以直接下載gradle之后放在對(duì)應(yīng)的目錄里
//或者修改 根目錄下的文件bulid.gradle ,使用國(guó)內(nèi)阿里云倉(cāng)庫(kù)
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 隱式啟動(dòng)和顯式啟動(dòng) activity
1.顯式啟動(dòng) //明確表示要啟動(dòng)的是什么activity,是activity的具體實(shí)例
Intent intent =new Intent(this,SecondActivity.class);
startActivity(intent);

2.隱式啟動(dòng)Intent // 只是指定一個(gè)action,可能是瀏覽器動(dòng)作,可能是打開支付界面動(dòng)作
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到一個(gè)列表
// 去掉action匹配失敗的intent filter
// 去掉url數(shù)據(jù)匹配失敗的intent filter
// 去掉category匹配失敗的Intent filter
// 剩下的intent filter 數(shù)量是否為0

                        //否
                        //查找失敗,拋出異常

// 是
// 將匹配成功的intent filter安優(yōu)先級(jí)排序
// return 最高優(yōu)先級(jí)的Intent filter

////DynamicLoadApk *///////
宿主里面的activity是:
<activity name="****.proxyActivity >
<action ***/>
<***** />
</activity>

onclick->通過DLIntent傳遞了要啟動(dòng)的包名和activity名,之后
DLProxyActivity.onCreate() 方法里面調(diào)用來(lái)了 DLProxyImpl的
impl.onCreate(getIntent()); -->launchTargetActivity();
mClass = intent.getStringExtra(DLConstants.EXTRA_CLASS) //從intent里面得到類名
class<?> localClass = getClassLoader().loadClass(mClass); //加載類
Constructor<?> localConstructor = localClass.getConstructor(new Class[] {}); //得到構(gòu)造函數(shù)
Object instance = localConstructor.newInstance(new Object[] {}); //反射生成實(shí)際插件的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); // 調(diào)用插件activity的onCreate函數(shù),DLConstants.FROM判斷是不是動(dòng)態(tài)加載

// DLProxyActivity 作為插件activity的宿主,在宿主中存在,管理插件activity的生命周期

// ProxyActivity 生命周期同步

//在 ProxyActivity 生命周期里用反射調(diào)用插件 Activity 相應(yīng)生命周期的方法,簡(jiǎn)單粗暴;
//把插件 Activity 的生命周期抽象成接口,在 ProxyActivity 的生命周期里調(diào)用;
//dynamic-load-apk 向我們展示了許多優(yōu)秀的處理方法
把 Activity 關(guān)鍵的生命周期方法抽象成 DLPlugin 接口,ProxyActivity 通過 DLPlugin 代理調(diào)用插件 Activity 的生命周期;
設(shè)計(jì)一個(gè)基礎(chǔ)的 BasePluginActivity 類,插件項(xiàng)目里使用這些基類進(jìn)行開發(fā),可以以接近常規(guī) Android 開發(fā)的方式開發(fā)插件項(xiàng)目;
以類似的方式處理 Service 的問題;
處理了大量常見的兼容性問題(比如使用 Theme 資源時(shí)出現(xiàn)的問題);
處理了插件項(xiàng)目里的 so 庫(kù)的加載問題;
使用 PluginPackage 管理插件 APK,從而可以方便地管理多個(gè)插件項(xiàng)目;

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 都可以對(duì)類進(jìn)行加載
// class.forName() 除了將類的.class文件加載到j(luò)vm中,還會(huì)對(duì)類進(jìn)行解析,執(zhí)行static{}代碼
// classLoader只做一件事,就是將.class文件加載jvm中,不會(huì)執(zhí)行static{}代碼

// private 類內(nèi)可見
// protected 包內(nèi)可見
// public 全部可見

// try{
// Constructor<?> constructor = Activity.class.getConstructor();
// Object o = constructor.newInstance();
// Activity activity = (Activity)o;
// activity.onStart(); /***這里報(bào)錯(cuò)了,因?yàn)閛nStart()是protected方法,是包內(nèi)訪問權(quán)限,在android.app.Activity里面才可以訪問,假如想要訪問onStart()方法的話,要反射
// 修改onStart方法的修飾符,將他改為public,所以DLProxyActivity里面才實(shí)現(xiàn)了一套public接口來(lái)管理生命周期
// }catch (Exception e){
//
// }

//DLProxyActivity假如不通過DLPlugin接口管理生命周期的話
protected void onStop() {
this.mRemoteActivity.onStop(); //報(bào)錯(cuò),訪問了android.app.Activity里面的protected方法
super.onStop();
}

//DLBasePluginActivity
public void onStop(){
if(this.mFrom == 0){ // 是自然加載
super.onStop();
}
// 為什么不是自然加載就直接返回了呢,因?yàn)榇藭r(shí)DLBasePluginActivity只是一個(gè)普通的activity對(duì)象
//它不應(yīng)該參與生命周期的管理,//后面的繼承于DLBasePluginActivity的可以在這里清除數(shù)據(jù),或者修改其它
//例如: this.listViewHashMap.clearALl(); this.state = STATE_STOP,this.registerNotify(***);

}

//同一個(gè)class經(jīng)過不同的類加載器加載是不同的
// gradle ?部分出錯(cuò)了??
// 動(dòng)態(tài)加載時(shí)候 ,plugin模塊的build.gradle 應(yīng)該改為
dependencies {
provided fileTree(dir: 'libs', include: ['
.jar'])
//provided 意思是編譯時(shí)候使用,但是不打包到apk中,這樣做是因?yàn)樗拗黜?xiàng)目里面已經(jīng)包含了dl-lib.jar了,
//如果插件也有dl-lib.jar 就會(huì)加載兩次了,,報(bào)錯(cuò)
**
//必須使用宿主的DL框架加載plugin
.........
}

// 可以通過gradle來(lái)計(jì)算bulid時(shí)間,或者在bulid過程中執(zhí)行某些函數(shù),或者排除某些.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 表示該功能對(duì)于app是必須有的,如果某一個(gè)設(shè)備不具備該功能,
//googlePlay商店將會(huì)對(duì)該設(shè)備隱藏該app
//false 表示該功能對(duì)于app來(lái)說不是必需的,假如某一個(gè)設(shè)備不具備該功能
// googlePlay商店依然對(duì)該設(shè)備顯示該app

android:glEsVersion="Integer"  
//指定 open GL的版本號(hào),只針對(duì)open GL功能 游戲開發(fā)時(shí)候要使用到openGL
/>  // uses-feature 并不獲取權(quán)限,只是說明該app有著該權(quán)限的特征

<uses-permission android:name="String"
// 聲明要獲取的權(quán)限,可以是一個(gè)標(biāo)準(zhǔn)的系統(tǒng)權(quán)限
// 也可以是app自己定義的一個(gè)權(quán)限
android:maxSdkVersion="Integer"
// 此權(quán)限應(yīng)授予應(yīng)用的最高 API 級(jí)別。
// 如果應(yīng)用需要的權(quán)限從某個(gè) API 級(jí)別開始不再需要,則設(shè)置此屬性很有用。

// 例如,從 Android 4.4(API 級(jí)別 19)開始,
// 應(yīng)用在外部存儲(chǔ)空間寫入其特定目錄(getExternalFilesDir() 提供的目錄)時(shí)不再需要請(qǐng)求 WRITE_EXTERNAL_STORAGE 權(quán)限。
// 但 API 級(jí)別 18 和更低版本需要此權(quán)限。
// 因此,您可以使用如下聲明,聲明只有 API 級(jí)別 18 及以前版本才需要此權(quán)限:
/>

// uses-feature的作用更像是一個(gè)過濾器,
// google play 商店會(huì)根據(jù)該標(biāo)簽來(lái)過濾設(shè)備,
// 比如用戶在uses-feature中聲明了要使用相機(jī),
// 這時(shí)候在google play商店中該app就不再對(duì)沒有照相機(jī)的設(shè)備顯示。
// 但是,如果用戶同時(shí)也設(shè)置了uses-feature的屬性android:required 為false的話,
// google play商店仍然會(huì)對(duì)沒有照相機(jī)的設(shè)備顯示該app。

// 假如現(xiàn)在需要開發(fā)一個(gè)app,它是一個(gè)聊天的工具,
// 包含給對(duì)方發(fā)送照片的功能,所以會(huì)用到系統(tǒng)的照相機(jī)。
// 但是,該app的主要功能還是聊天,
// 就算是在一個(gè)沒有照相機(jī)的手機(jī)上也應(yīng)該能夠讓它正常地使用聊天的功能。

<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 獲取雙卡手機(jī)IMEI,IMSI,ICCID

1.首先要添加權(quán)限
//<uses-permission android:name="android.permission.READ_PHONE_STATE" />
// IMEI 與你的手機(jī)是綁定關(guān)系 用于區(qū)別移動(dòng)終端設(shè)備
// IMSI 與你的手機(jī)卡是綁定關(guān)系 用于區(qū)別移動(dòng)用戶的有效信息 IMSI是用戶的標(biāo)識(shí)。
// ICCID ICCID是卡的標(biāo)識(shí),由20位數(shù)字組成
// ICCID只是用來(lái)區(qū)別SIM卡,不作接入網(wǎng)絡(luò)的鑒權(quán)認(rèn)證。而IMSI在接入網(wǎng)絡(luò)的時(shí)候,會(huì)到運(yùn)營(yíng)商的服務(wù)器中進(jìn)行驗(yàn)證。

@RequiresApi(api = Build.VERSION_CODES.O) //或者 @TargetAPi(22) ???
public void check(View view) {

    TelephonyManager telephonyManager = (TelephonyManager) this
            .getSystemService(TELEPHONY_SERVICE);// 取得相關(guān)系統(tǒng)服務(wù)

    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", "運(yùn)行商名字--" + 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);
}

//http://www.lxweimin.com/p/1269e4ba99c9
// 獲取卡的信息,,主要是讀取數(shù)據(jù)庫(kù)實(shí)現(xiàn)的
// /data/data/com.android.providers.telephony/databases/telephony.db //數(shù)據(jù)庫(kù)狀態(tài)
// table siminfo
_id icc_id sim_id display_name carrier_name name_source color number display****

//每次插入一張新SIM卡(這張卡沒有插入到手機(jī))時(shí)候,在數(shù)據(jù)庫(kù)插入一條記錄
//插入的時(shí)候_id字段從1開始每次增1
//每次移除一張SIM卡,sim_id字段設(shè)置為-1,但是這條記錄不會(huì)刪除,//表示這張卡曾經(jīng)插入過
//但是被移除了,就是說該卡現(xiàn)在不是activite的,處于不可用狀態(tài)

讀取第二張卡 // 獲取subcription id
讀取數(shù)據(jù)庫(kù) 取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", "---------------------------------");
        }
    }
}

// 通過反射調(diào)用獲取IMSI
反射調(diào)用帶有參數(shù)的getSubscriberId(subId)
//但是這個(gè)方法是@Hide的
//而且在不同的android版本會(huì)出現(xiàn)不同的實(shí)現(xiàn)
//subId在5.0代碼中傳入的是long類型參數(shù)
//5.1-7.1.1 傳入的是int類型參數(shù)

public String getSubscriberId(int subId) {
TelephonyManager telephonyManager = (TelephonyManager) this
.getSystemService(TELEPHONY_SERVICE);// 取得相關(guān)系統(tǒng)服務(wù)
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;
}

// 根據(jù)不同sdk版本執(zhí)行不同代碼
// @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 系統(tǒng)的版本
    /***/
}

//DEVICE_ID 就是imei 手機(jī)設(shè)備唯一標(biāo)識(shí)符
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) {
                    // 賦予默認(rèn)值
                    ex.printStackTrace();
            }
            return macSerial;
    }

// 獲取meta數(shù)據(jù)
// ApplicationInfo appInfo = this.getPackageManager()
// .getApplicationInfo(getPackageName(),
// PackageManager.GET_META_DATA);
// String msg=appInfo.metaData.getString("data_Name");
// Log.d(TAG, " msg == " + msg );

// onPreExecute 是在主線程執(zhí)行的

//遠(yuǎn)控木馬 https://github.com/xingda920813/HelloDaemon /github的守護(hù)服務(wù)工程
// helloDaemon android 服務(wù)保存/常駐

//為什么遠(yuǎn)控木馬是 BadgeProvider
// 因?yàn)锽adgeProvider 是android常見的一個(gè)服務(wù),可以劫持加載

//getStackElement()[4] ---> generateTag()
//StackTraceElement caller
// caller.getClassName()
// caller.getMethodName();
// caller.getLineNumber();

// 讀寫分離
// 通過公共的數(shù)據(jù)庫(kù)訪問數(shù)據(jù),so層連接網(wǎng)絡(luò)并獲取數(shù)據(jù),java層解密數(shù)據(jù),并執(zhí)行命令
// 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 要執(zhí)行命令的內(nèi)容
// 讀取/proc/目錄下的文件
// 解析pid
// str=訪問 /proc/+pid+/cmdline
// if str==procName 正在運(yùn)行,找到了,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路徑的內(nèi)容 */
}

// 插件肯定是直接往數(shù)據(jù)庫(kù)插入數(shù)據(jù)就可以了,假如個(gè)個(gè)都自己調(diào)用socket
// 去和服務(wù)器交流,,那樣不是累死???
// 數(shù)據(jù)也很難統(tǒng)一,比如加密標(biāo)準(zhǔn),消息類型,
// 肯定應(yīng)該有個(gè)主服務(wù),在執(zhí)行消息循環(huán),不斷從數(shù)據(jù)庫(kù)取出東西,統(tǒng)一
// 標(biāo)準(zhǔn)發(fā)到服務(wù)器
// 數(shù)據(jù)庫(kù)通常作為接口,作為消息傳遞的橋梁

// java層插入處理數(shù)據(jù) so層加密,發(fā)生,接收數(shù)據(jù)

// linux &表示后臺(tái)執(zhí)行

// runNativeAndroidClient
// 先從宿主釋放資源生成AndroidClientSo
// 獲取so的路徑,后臺(tái)執(zhí)行so+args+ &
// 死循環(huán)定時(shí)執(zhí)行

// so層回調(diào) BootReceiverd的onReceive-> startService(adobe_service_intent);
// ->startCommand()--->

// TaskDataManager //處理數(shù)據(jù)庫(kù),添加正在運(yùn)行的任務(wù)或者運(yùn)行完成的任務(wù)

// 批量重命名 // shift + f6

// 獲取系統(tǒng)信息,根據(jù)不同的信息請(qǐng)求不同的so,例如:libX86Linux2.2.3Android5.0.so

// 命名規(guī)范 所見即所得 函數(shù)規(guī)范

//所有編程相關(guān)的命名均不能以下劃線或美元符號(hào)開始 系統(tǒng)內(nèi)核也使用了_name這樣的變量
// 例如 _isSu // 系統(tǒng)內(nèi)核也有一個(gè)_isSu

// android stdio 格式化代碼 快捷鍵 ctrl+alt+L

// _表示類內(nèi)成員,類似m

// context _context

//Thread.CurrentThread().getStackTrace() //獲取堆棧的軌跡 ,因?yàn)槭堑怪卣{(diào)的
// 所以可以通過Thread.CurrentThread().getStackTrace()[3] 獲取,每多一重方法入口
// index+1
// 如: LogUtil中的
//private static StackTraceElement getCallerStackTraceElement() {
// return Thread.currentThread().getStackTrace()[4];
// }

// 因?yàn)檫@里又多了一重方法,所以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));
}

// 所有代碼都應(yīng)該考慮用 try{}catch(Exception e)finally{} 機(jī)制

// mgrDownloadFile1 下載文件
// mgrDownloadFile2 下載文件完成,重命名文件 //是否mgrDownloadFileFinished()更好

// getLaunchIntentForPackage() //獲取啟動(dòng)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{
// 沒有默認(rèn)入口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的全路徑和名稱
// 需要啟動(dòng)的目標(biāo)activity在androidMainfest.xml中的屬性Export="true"

// packageManager.queryIntentActivities() 查詢是否有能解析指定Intent的應(yīng)用
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() 兩種方式;

方式三 隱式啟動(dòng),使用 Intent.resolveActivity()、Intent.resolveActivityInfo() 、
packageManager.queryIntentActivities() 三種方式均可。

//ANDROID_ID 16進(jìn)制的64位字符,恢復(fù)出廠設(shè)置,該值可能會(huì)變???
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 數(shù)據(jù)庫(kù)的內(nèi)容
Cursor cursor = context.getContentResolver().query(Uri.parse("content://sms"),null,null,null,"date desc");
int columnCount = cursor.getColumnCount(); // 得到列數(shù)
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 廣播
// 廣播分為可終止和不可以終止的
// 不可終止的會(huì)發(fā)給所有app
// 可終止的按照優(yōu)先級(jí)發(fā)生,假如某個(gè)receiver終止了,那么以后的都不會(huì)接收到

// android 4.4 以后,只有默認(rèn)的短信應(yīng)用才能修改短信
// 但是其他應(yīng)用可以偵聽SMS——RECEIVED_ACTION廣播(不可以中斷的廣播)來(lái)監(jiān)聽短信變化

// 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) // 新增了動(dòng)態(tài)權(quán)限
權(quán)限分類:
// noraml ,dangerous,signature,signatureOrSystem //(system app 權(quán)限)
權(quán)限組 // 每個(gè)權(quán)限組可以包含多個(gè)權(quán)限

  • 如果應(yīng)用申請(qǐng)?jiān)L問一個(gè)危險(xiǎn)權(quán)限,而此應(yīng)用目前沒有對(duì)應(yīng)的權(quán)限組內(nèi)
    的任何權(quán)限,系統(tǒng)會(huì)彈窗提示用戶要訪問的權(quán)限組(注意不是權(quán)限)。例如無(wú)
    論你申請(qǐng)READ_CONTACTS還是WRITE_CONTACTS,
    都是提示應(yīng)用需要訪問聯(lián)系人信息。
  • 如果用戶申請(qǐng)?jiān)L問一個(gè)危險(xiǎn)權(quán)限,而應(yīng)用已經(jīng)授權(quán)同權(quán)限組的其他
    權(quán)限,則系統(tǒng)會(huì)直接授權(quán),不會(huì)再與用戶有交互。例如應(yīng)用已經(jīng)請(qǐng)求并
    授予了READ_CONTACTS權(quán)限,那么當(dāng)應(yīng)用申請(qǐng)WRITE_CONTACTS時(shí),系統(tǒng)會(huì)
    立即授予該權(quán)限。下面為危險(xiǎn)權(quán)限和權(quán)限組:

先檢查權(quán)限
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.WRITE_CALENDAR);

請(qǐng)求權(quán)限:
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_CODE);

處理權(quán)限
@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

// 設(shè)計(jì)模式 // 代碼規(guī)范
// 網(wǎng)上的代碼,應(yīng)該再封裝一層,為自己定義好的接口

// PermissionsDispatcher
dependencies {
compile 'com.github.hotchemi:permissionsdispatcher:${latest.version}'
annotationProcessor 'com.github.hotchemi:permissionsdispatcher-processor:${latest.version}'
}

@RuntimePermissions 注冊(cè)一個(gè) Activity 或 Fragment 用于處理權(quán)限
@NeedsPermission 注解一個(gè)方法,說明需要什么權(quán)限(一個(gè)或多個(gè))
@OnShowRationale 注解一個(gè)方法,解釋為什么需要這些權(quán)限
@OnPermissionDenied 注解一個(gè)方法,當(dāng)用戶拒絕授權(quán)時(shí)將調(diào)用該方法
@OnNeverAskAgain 注解一個(gè)方法,當(dāng)用戶選擇了 "不再提醒" 將調(diào)用該方法

@NeedsPermission({ Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO })

android為了防止第三方軟件攔截短信和亂寫入短信記錄,
在4.4之后,設(shè)置了只有默認(rèn)的短信應(yīng)用才會(huì)有權(quán)限操作短信數(shù)據(jù)庫(kù)

ASyncTask //
onPreExecute() --> doInBackground() --> publishProgress() --> onProgressUpdate() --> onPostExecute()

ASyncTask
異步任務(wù)的實(shí)例必須在UI線程執(zhí)行
execute(Params...params)必須在UI線程中調(diào)用
不要手動(dòng)調(diào)用onPreExecute(),doInBackground(Params... params),onProgressUpdate(Progress... values)
,onPostExecute(Result result)這幾個(gè)方法
不能在doInBackground(Params... params)中更改UI組件的信息。
一個(gè)任務(wù)實(shí)例只能執(zhí)行一次,如果執(zhí)行第二次將會(huì)拋出異常。

//onPreExecute onPostExecute 是在UI線程執(zhí)行的
// AsyncTask 在doInBackGround里面執(zhí)行耗時(shí)任務(wù),將結(jié)果返回給
// UI線程顯示

// AsyncTask 實(shí)則是onPreExecute在主線程執(zhí)行,但是doInBackGround是新開始一個(gè)線程執(zhí)行的,
// 執(zhí)行完成后,offer方法往隊(duì)列插入一個(gè)消息,
// 主線程不停地從消息隊(duì)列取出方法,所以假如主線程Sleep了的話,onPostExecute方法將永遠(yuǎn)不會(huì)執(zhí)行
// onPreExcute onPostExcute 修改UI狀態(tài)

// 不要在onPreExcute里面執(zhí)行Sleep等方法,否則調(diào)用多個(gè)AsyncTask時(shí)候
// 主線程會(huì)卡在onPreExcute方法里面,而其他AsyncTask的onPostExcute方法不會(huì)執(zhí)行

//Intent 傳遞對(duì)象的方法
Serializable Parcelable JSON

// 正則表達(dá)式
[,],(,) 需要轉(zhuǎn)義 /) /( /[ /] 這樣

// 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字符串,其中的數(shù)字4是縮進(jìn)字符數(shù)  
        } 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 從默認(rèn)匹配的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時(shí)候需要新啟動(dòng)一個(gè)FLAG_ACTIVITY_NEW_TASK
// MainActivity直接讀取數(shù)據(jù)庫(kù)的話,好像可能讀取到很多重復(fù)記錄,需要select 之后 order desc 之后limit 0,1 ??

// PreferenceManager.getDefaultSharedPreferences(mContext).getBoolean("Get", false);
// 為什么返回了true 因?yàn)檎{(diào)試過程中可能突然中斷,導(dǎo)致onPostExecute的方法沒有執(zhí)行
// 所以卡在死循環(huán)那里了
// 所以可以卸載app重新安裝
// while 循環(huán)的時(shí)候,應(yīng)該考慮再加一層時(shí)間判斷????

// Date date = new Date(millsecond1000); // millsecond 為納秒數(shù),不1000,會(huì)溢出,導(dǎo)致顯示為1970
// String 比較應(yīng)該用equals 不應(yīng)該用==(內(nèi)存比較)
// 插入數(shù)據(jù)庫(kù)的操作通常不會(huì)出錯(cuò),通常出錯(cuò)的是獲取信息的過程,不同版本的兼容性會(huì)導(dǎo)致有異常

// listView 可以直接顯示的數(shù)據(jù)為BitMap
// 所以byte[]數(shù)組,可以考慮轉(zhuǎn)為Bitmap類型
private Bitmap byte2Bitmap(byte[] b){
if(b.length!=0){
return BitmapFactory.decodeByteArray(b,0,b.length);
}else{
return null;
}
}

// hashMap JsonObject 里面表示一個(gè)null對(duì)象不能用null表示,因?yàn)槟J(rèn)就是null
// 應(yīng)該用"null"

// run窗口只有在run環(huán)境下才生效,debug下無(wú)效

// Intent 傳遞Bitmap時(shí)候會(huì)把bitmap.toString();得不到bitmap實(shí)際對(duì)象

//不能直接傳遞大于40k的圖片,把bitmap存儲(chǔ)為byte數(shù)組,然后再通過Intent傳遞。

// android ImageView 默認(rèn)顯示:
// 在xml代碼中加 android:src="@drawable/image"
// 在java代碼中設(shè)置 ImageView imageView = findViewById(R.id.imageView);
// imageView.setImageResource(R.drawable.image);

// 因?yàn)橹骶€程睡眠了??? 所以卡在了onPreExcute里面

// 查詢數(shù)據(jù)庫(kù)的時(shí)候是否應(yīng)該清空一下???

// 在這里寫的<TextView></TextView> // 將顯示不出,因?yàn)榍懊娴腖inearLayout布局已經(jīng)android:layout_width="match_parent"
// android:layout_height="match_parent" 占據(jù)了所有空間,所以TextView沒有空間了

// ok--->insert message
// fail ---> insert printStream(new Exception(msg)).toString();

// 加鎖設(shè)置別人訪問的時(shí)候睡眠,等待有可用資源時(shí)候再調(diào)用

// Android 判斷Service是否已經(jīng)啟動(dòng)
// 采用Service來(lái)進(jìn)行百度定位,并且將數(shù)據(jù)上傳到服務(wù)
// 器上遇到了一個(gè)問題:在真機(jī)中使用清理內(nèi)存來(lái)關(guān)閉程序的之后,Service
// 會(huì)被關(guān)閉,但是過幾秒中,它又會(huì)自動(dòng)重啟;重啟就算了,而且再次登陸系統(tǒng)
// 的時(shí)候,又會(huì)開啟一個(gè)一樣的服務(wù),在LogCat中就會(huì)看到每次都獲取到兩次的
// 定位數(shù)據(jù)。然后想想是否可以在建立Service之前判斷這個(gè)服務(wù)有沒
// 有被創(chuàng)建?只要能做這個(gè)判斷,那么服務(wù)存在我們就不管它,如果不存在則創(chuàng)建,

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 必須注冊(cè) 同Activity
// 動(dòng)態(tài)加載,需要聲明 DLProxyActivity 和 DLProxyService

// start service 它的生命周期只有三個(gè)階段onCreate,onStartCommand(),onDestory() 方法

// 2.0 API后 onStart()方法被 onStartCommand()取代了
// service 在后臺(tái)工作,界面清除了,service還存在

onStartComand使用時(shí),返回的是一個(gè)(int)整形。
這個(gè)整形可以有四個(gè)返回值:start_sticky、start_no_sticky、START_REDELIVER_INTENT、START_STICKY_COMPATIBILITY。
它們的含義分別是:
1):START_STICKY:如果service進(jìn)程被kill掉,保留service的狀態(tài)為開始狀態(tài),但不保留遞送的intent對(duì)象。隨后系統(tǒng)會(huì)嘗試重新創(chuàng)建service,由于服務(wù)狀態(tài)為開始狀態(tài),所以創(chuàng)建服務(wù)后一定會(huì)調(diào)用onStartCommand(Intent,int,int)方法。如果在此期間沒有任何啟動(dòng)命令被傳遞到service,那么參數(shù)Intent將為null。
2):START_NOT_STICKY:“非粘性的”。使用這個(gè)返回值時(shí),如果在執(zhí)行完onStartCommand后,服務(wù)被異常kill掉,系統(tǒng)不會(huì)自動(dòng)重啟該服務(wù)
3):START_REDELIVER_INTENT:重傳Intent。使用這個(gè)返回值時(shí),如果在執(zhí)行完onStartCommand后,服務(wù)被異常kill掉,系統(tǒng)會(huì)自動(dòng)重啟該服務(wù),并將Intent的值傳入。

// 調(diào)用onStartCommand---->onStart //

//聲明服務(wù)需要聲明android:enable
<service
android:name="com.flash18.stage_sevice"
android:enabled="true"
//沒有聲明該屬性
// startService無(wú)異常,但是onStart方法不執(zhí)行
android:priority="1000" />
<service
android:name="com.ryg.dynamicload.DLProxyService"
android:enabled="true" //必須的 // 非常重要???
//沒有聲明該屬性
// startService無(wú)異常,但是onStart方法不執(zhí)行
android:priority="1000"></service>

// 調(diào)用系統(tǒng)照相機(jī) 照相
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, "系統(tǒng)相機(jī)拍照完成,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, "默認(rèn)content地址:"+data.getData());
         iv_CameraImg.setImageURI(data.getData());
     }
 }

surfaceView 核心在于提供了兩個(gè)線程:UI線程和渲染線程
// 1.所有SurfaceView和SurfaceHolder.Callback的方法都應(yīng)該在UI線程調(diào)用
// 渲染線程所要訪問的各種變量應(yīng)該作同步處理
// 由于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){} //在創(chuàng)建時(shí)激發(fā),一般在這里調(diào)用畫圖的線程。

(3)public void surfaceDestroyed(SurfaceHolder holder) {} //銷毀時(shí)激發(fā),一般在這里將畫圖的線程停止、釋放。

//
// startView 配置攝像頭參數(shù),前置還是后置,圖片大小,
// mCamera.takePicture(null,mPictureCallback,mPictureCallback);
// /data/data/com.abc.ipqui.xyz/cache/audio/

// 直接調(diào)用系統(tǒng)的相機(jī)會(huì)產(chǎn)生一個(gè)界面
// hardsoft 訪問camera surfaceView 直接拍照

// surfaceCreated 都在主線程執(zhí)行 @MainThread 所以不應(yīng)該執(zhí)行太多代碼,,
// surfaceChanged @MainThread //主界面刷新的頻率為16ms時(shí)方為流暢
// surfaceDestoryed @MainThread

// surfaceView 實(shí)則上就是view
// 在activity里面調(diào)用 mCameraSurfaceView = (CameraSurfaceView) findViewById(R.id.view_camera);
// 時(shí)候,會(huì)自動(dòng)調(diào)用surfaceCreated方法,在activity銷毀時(shí)候,會(huì)自動(dòng)調(diào)用surfacedestoryed方法

// surfaceChanged 當(dāng)窗口首次創(chuàng)建時(shí)候,肯定會(huì)調(diào)用此方法的
// 當(dāng)屏幕從垂直到水平旋轉(zhuǎn),,肯定也應(yīng)該改變

// surfaceView 生命周期
// 當(dāng)程序第一次啟動(dòng)時(shí)候,調(diào)用view的構(gòu)造函數(shù)->surfaceCreated->surfaceChanged
// 按HOME鍵時(shí),調(diào)用surfaceDestroyed;點(diǎn)擊圖標(biāo)返回程序時(shí),調(diào)用surfaceCreated->surfaceChanged
// 按返回鍵,調(diào)用surfaceDestoryed,點(diǎn)擊圖標(biāo)返回程序時(shí),調(diào)用view的構(gòu)造函數(shù) 因?yàn)檫@時(shí)候activity已經(jīng)
// 銷毀了,所以肯定會(huì)調(diào)用activity的onCreate方法,之后調(diào)用view的構(gòu)造函數(shù)
// -->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");

// 錄音權(quán)限判斷
// 小于android 6.0 判斷錄音數(shù)據(jù)的合法性,比如byte[]數(shù)組里面是否全為0
// 大于android 6.0 用系統(tǒng)的API:checkPermission
if(audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING){
Log.d("TAG","permission denied");
return;
}

Android錄音權(quán)限被禁解決方案
1,第一種,就是start的時(shí)候會(huì)報(bào)異常,這種我們把它包在try catch中即可捕獲到異常。在此不多累述。
2,第二種,就是不報(bào)異常,正常執(zhí)行,這種情況我們沒辦法去判斷系統(tǒng)是否禁止了我們的app的錄音權(quán)限。
(1)AudioRecord判斷方法:

int readSize = 0;

/--實(shí)時(shí)錄音寫數(shù)據(jù)--/
readSize = audioRecord.read(buffer,0,minBufferSize);
if (readSize < 0) {
//錄音出現(xiàn)異常
}

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/" 失敗

/**
根據(jù)文件路徑,遞歸創(chuàng)建文件
*/
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(); 遞歸創(chuàng)建目錄
}

// smsCursor 默認(rèn)index為-1
// smsCursor.getPosition() 獲取index
// 所以剛開始的時(shí)候smscursor.moveToFirst 和smscursor.moveToNext 都是 0
// moveToNext 簡(jiǎn)單將index+1
// moveToFirst 將index置0

// 所以可以用
while(smsCursor.moveToNext()){
/***************/
}///查詢信息

// android 4.4后,只有默認(rèn)短信應(yīng)用才能刪除短信,

什么是Premium Rate SMS?

Premium Rate SMS是一種付費(fèi)短信模式,通過發(fā)送特殊的文本信息,用戶自動(dòng)扣費(fèi)。例如通過手機(jī)短信捐款,辦理付費(fèi)業(yè)務(wù)等。最新ztorg木馬利用該模式來(lái)牟利,這項(xiàng)技術(shù)讓黑客的利益最大化,并降低了被發(fā)現(xiàn)的風(fēng)險(xiǎn)。

Ztorg為何這么難被檢測(cè)到?

多模擬器檢測(cè)功能,它可以檢測(cè)到Android SDK模擬器,
如genymotion,BlueStacks, buildroid。它還檢測(cè)設(shè)備感染環(huán)境,
這些檢測(cè)很難被繞過。 使用基于XOR的字符串混淆。 采用DES-CBC加
密遠(yuǎn)程服務(wù)器進(jìn)行通信。 從遠(yuǎn)程服務(wù)器下載、安裝和啟動(dòng)Android應(yīng)用
程序。 自去年 9 月以來(lái),Ztorg 惡意木馬大約 100 次繞過 Google 的
自動(dòng)化惡意程序檢查程序進(jìn)入官方應(yīng)用市場(chǎng)。
被稱為 Magic Browser 的 Ztorg 惡意應(yīng)用下架前被下載量超過 5 萬(wàn)次。

// android 4.4 之前是有序廣播 可以終止
// android 4.4 之后 無(wú)序廣播,不可以終止,默認(rèn)短信還接收一個(gè)額外的通知

// 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 當(dāng)前連接的ssid判斷

// Toast不顯示

// 是否調(diào)用了show()
// context 為null
// 在子線程調(diào)用Toast不會(huì)顯示,因?yàn)門oast并沒有在UI線程中調(diào)用
在主線程中: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 來(lái)獲取聯(lián)系人的ID和NAME

android.provider.ContactsContract.CommonDataKinds.Phone.CONTENT_URI 獲取聯(lián)系人的電話號(hào)碼

android.provider.ContactsContract.CommonDataKinds.Email.CONTENT_URI 獲取聯(lián)系人的郵箱地址

iterator 默認(rèn)index是 -1
所以代碼可以是
while(iterator.hasNext()){
// iterator.next();
}

String.format("%-16s","ss")
// 格式化字符串輸出 -表示左對(duì)齊
// "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 //得到文件修改時(shí)間
// os.path.getctime //得到文件創(chuàng)建時(shí)間
// os.path.getatime //得到文件最近訪問時(shí)間
方法
// 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無(wú)法安裝
// 1.AndroidMainfest.xml 中設(shè)置了apk屬性為testOnly
<application
...android:testOnly ="true"
...>
</application>
gradle版本為測(cè)試版本,非穩(wěn)定版本
2.gradle版本為測(cè)試版本,非穩(wěn)定版本
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.4.0-alpha3' //版本為測(cè)試版
}
}

eclipse // 默認(rèn)編碼gbk
android stdio //默認(rèn)編碼 utf-8

// public final void registerContentObserver(Uri uri,boolean notifyForDescendents,ContentObserver ovserver)
// 為指定的uri注冊(cè)一個(gè)ContentObserver派生類實(shí)例,當(dāng)給定的Uri發(fā)生改變時(shí)候,回調(diào)該實(shí)例對(duì)象去處理
// 參數(shù):uri 需要觀察的Uri // 需要在UriMatcher里注冊(cè)
// notifyForDescendents 為false 表示精確匹配,即只匹配該uri
// 為true 表示可以匹配其派生的uri

// 監(jiān)聽指定uri對(duì)應(yīng)的數(shù)據(jù)庫(kù),當(dāng)數(shù)據(jù)庫(kù)發(fā)生改變時(shí)候,會(huì)回調(diào)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創(chuàng)建module
Phone & Table Module,創(chuàng)建手機(jī)類型或平板電腦類型的module,換句話說創(chuàng)建手機(jī)或平板電腦的Android項(xiàng)目,通常Android開發(fā)者都默認(rèn)選中該選項(xiàng),除非想要開發(fā)Android Watch(智能手表)

Android Library,創(chuàng)建Android類庫(kù),將平時(shí)總結(jié)的TeachCourse Android 源碼Demo封裝成類庫(kù)的形式,想要選中該項(xiàng),然后可以在多個(gè)module中引用

Android Wear Module,創(chuàng)建智能手機(jī)的Android項(xiàng)目,該module用于創(chuàng)建智能手表時(shí),默認(rèn)添加一些依賴屬性

Android TV Module,創(chuàng)建智能電視的Android項(xiàng)目,開發(fā)的應(yīng)用程序主要針對(duì)智能電視,運(yùn)行和安裝在TV上,為什么需要將其和Phone & Table Module區(qū)分開?主要TV Module和Phone &Table Module在尺寸和圖標(biāo)、布局有比較大的出入,獨(dú)立開來(lái),比較方便出來(lái)

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:創(chuàng)建ImageReader,構(gòu)建VirtualDisplay
// 5:最后就是通過ImageReader截圖,就可以從ImageReader里獲得Image對(duì)象。
// 6:將Image對(duì)象轉(zhuǎn)換成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);
}
}
}

創(chuàng)建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);

當(dāng)VirtualDisplay被創(chuàng)建出來(lái)時(shí),也就是createVirtualDisplay調(diào)用后,
你在真實(shí)屏幕上的每一幀都會(huì)輸入到Surface參數(shù)里。也就是說,
如果你放個(gè)SurfaceView,然后傳入SurfaceView的Surface
那么你在屏幕上的操作都會(huì)顯示在SurfaceView里(這里我們后面錄屏?xí)v)。
我們這里傳入的是ImageReader的Surface。這其中的邏輯我的理解是這樣的,
真實(shí)屏幕的每一幀都都會(huì)傳給ImageReader,根據(jù)ImageReader的maxImages參數(shù),
比如說maxImages是2,那么ImageReader始終保持兩幀圖片,但這兩幀圖片是一直隨
著真實(shí)屏幕的操作而更新的 // 通常設(shè)置為1

在創(chuàng)建VirtualDiaplay 的時(shí)候創(chuàng)建Surface
// 創(chuàng)建VirtualDiaplay的時(shí)候會(huì)傳入一個(gè)SurfaceView的Surface
mediaProjection.createVirtualDisplay("ScreenShot",width,height,dpi,DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
surfaceView.getHolder().getSurface(),null,null);

當(dāng)創(chuàng)建VirtualDisplay時(shí),真實(shí)屏幕就映射到Surface里面,所以
只要把Surface對(duì)象轉(zhuǎn)為mp4格式就可以了,
// 轉(zhuǎn)換為mp4 肯定要解碼
// 所以需要輔助類 Util // Helper ??
// MediaCodec MediaMuxer
// MediaCodec 生成一個(gè)Surface用來(lái)接收屏幕的輸出
// MediaMuxer 封裝mp4格式的視頻

byte數(shù)組 根據(jù)第一個(gè)字節(jié) 轉(zhuǎn)為對(duì)應(yīng)的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); // 封裝數(shù)據(jù)包
byte []after = Cryptor.encrypt(c,before); // 加密數(shù)據(jù)包
/*********

url 連接

**********/
byte []responseDecrypted = Cryptor.decrypt(c,response);
return PacketInfo.praseSolutions(responseDecrypted);

}

// registerReceiver(mScreenOffReceiver, new IntentFilter("android.intent.action.SCREEN_OFF"));

// 后臺(tái)服務(wù) ?;? 防止被系統(tǒng)干掉
// 在onStartCommand方法中返回START_STICKY,當(dāng)Service進(jìn)程被kill后,
// 系統(tǒng)會(huì)嘗試重新創(chuàng)建這個(gè)service,并保留service的狀態(tài)為開始狀態(tài),但不保留
// 傳遞的Intent對(duì)象,onStartCommand方法一定會(huì)調(diào)用

// 在onDestory里面重新啟動(dòng)自己,只要service運(yùn)行到onDestory,就重新啟動(dòng)

A a =new A();
B b=new B(a);
強(qiáng)引用 // 當(dāng)a為null的時(shí)候,由于B還有a的引用,所以a的內(nèi)存不會(huì)釋放
// 當(dāng)b=null時(shí)候,a的內(nèi)存才會(huì)釋放

弱引用 //當(dāng)a為null的時(shí)候,gc會(huì)回收內(nèi)存

// 服務(wù)?;顣r(shí)間段主要是在黑屏階段吧 ~~~~~~~~~
// 因?yàn)楫?dāng)屏幕關(guān)閉之后,說明用戶可能離開了,或者跑去吃夜宵了,不知道要多久才回來(lái)
// 假如這個(gè)時(shí)候,后臺(tái)服務(wù),,什么360,kkk,幾十個(gè)服務(wù)還在運(yùn)行的時(shí)候
// 系統(tǒng)耗電量肯定很大
// 所以系統(tǒng)肯定要干掉一些服務(wù)

// 所以主要接收的廣播 應(yīng)該是: onScreenOff 和 onScreenOn 通知
// 當(dāng)onScreenOff 的時(shí)候,主要服務(wù)?;?/p>

// 鎖屏的時(shí)候就彈出一個(gè)通知,解鎖的時(shí)候new service去掉通知 // 因?yàn)橛型ㄖ?,所以是前臺(tái)服務(wù)
// 雙進(jìn)程守護(hù),在ondestory時(shí)候,再次啟動(dòng)服務(wù) //有時(shí)候系統(tǒng)發(fā)威了,ondestory也不掉用了??
// 直接把你的內(nèi)存釋放了,
// 如一像素activity,防止亮屏?xí)r候 用戶發(fā)現(xiàn)??
// 循環(huán)播放一段音樂,,系統(tǒng)總不會(huì)連音樂也不給播放了吧,,// 可以以無(wú)聲實(shí)現(xiàn)

// 常見應(yīng)用?;?br> // 監(jiān)聽廣播,通過監(jiān)聽一些全局的靜態(tài)廣播,比如開機(jī)廣播,鎖屏廣播,網(wǎng)絡(luò)狀態(tài)廣播
// 高版本好像失效了???

//提高service的優(yōu)先級(jí) 比如 onStartCommand返回START_STICKY使系統(tǒng)內(nèi)存足夠的時(shí)候service能夠自動(dòng)啟動(dòng)
// 彈出通知,,配置service的優(yōu)先級(jí),但是這些方式只能在一定程度上緩解service被立馬回收,只要用戶
// 一鍵清理 或者系統(tǒng)回收,照樣無(wú)效

// 全局定時(shí)器,,定時(shí)檢測(cè)運(yùn)行后臺(tái)服務(wù)
// 雙service守護(hù),
// // 但是當(dāng)應(yīng)用被殺的時(shí)候,任何后臺(tái)service都無(wú)法運(yùn)行,也無(wú)法自行啟動(dòng)

// 雙進(jìn)程拉起
// 傳說中的使用ndk在底層fork出一個(gè)子進(jìn)程,來(lái)實(shí)現(xiàn)與父進(jìn)程之間的互拉,
// 但在高版本的android系統(tǒng)下,系統(tǒng)回收策略已經(jīng)變成進(jìn)程組了,如果系統(tǒng)要回收一個(gè)應(yīng)用,必然會(huì)殺死同
// 屬于同一個(gè)進(jìn)程組的所有進(jìn)程,因此最后導(dǎo)致雙進(jìn)程無(wú)法拉起

// app復(fù)活方案探討
// 使用JobScheduler android 5.0 允許app在將來(lái)達(dá)到一定條件時(shí)執(zhí)行指定的任務(wù),
// 即使app被強(qiáng)制停止,預(yù)定的任務(wù)仍然會(huì)被執(zhí)行
// <service
// android:name=".service.AliveJobService"
// android:permission="android.permission.BIND_JOB_SERVICE"/>

alloc_pages ->out_of_memory()->select_bad_process()->badness();

// 模擬前臺(tái)進(jìn)程 startForeground()
// abortBroadcast 中斷廣播 有序廣播,根據(jù)優(yōu)先級(jí)一個(gè)個(gè)接收,中斷后,其他的接收不到
// fakeActivity // 1像素activity ?;?/p>

// public static boolean isSystemInstallApp(Context context) {
// return !context.getPackageResourcePath().startsWith("/data/app/");
// }

public boolean isRunning(){
try{
this.process.exitValue(); // 假如進(jìn)程已經(jīng)退出了,應(yīng)該有個(gè)退出碼?
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();
// }

// 根據(jù)Build.Model 和 Kernel.version 獲取對(duì)應(yīng)的配置路徑
// 不同版本返回不同的解決計(jì)劃
// 每個(gè)計(jì)劃包括很多解決方案

// 不下載apk連不上網(wǎng),下載完apk就連上網(wǎng)絡(luò)

// 刪除工作區(qū)間的東西重啟eclipse時(shí)候 sdk adt圖標(biāo)消失
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}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,786評(píng)論 6 534
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,656評(píng)論 3 419
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,697評(píng)論 0 379
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,098評(píng)論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,855評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,254評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,322評(píng)論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,473評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,014評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,833評(píng)論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,016評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,568評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,273評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,680評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,946評(píng)論 1 288
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,730評(píng)論 3 393
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,006評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容