前幾天,為瞭解決一個問題,逆了一個小工具軟體。在這個過程發現了一些很有用的東西,在此跟大家分享一下。首先聲明幾點:1、逆出來的代碼,需要大量的人工分析,我現在只看了一點點;2、代碼不會公開,請不要向我要代碼,我怕麻煩~~~唉,做了這件壞事,內心忐~~~忑~~~啊!
一、通過編程實現對GPS的開關
在Android手機和模擬器上有一個管理GPS開關的設定介面,如下:
通過這個管理介面,我們可以對GPS進行管理,以實現我們的手機定位功能。曾經在網上搜集資料,希望找到通過代碼對GPS進行管理的源碼,也確實找到了一份代碼(稍後附上代碼),但是這份代碼在SDK 2.3及以上的版本中,始終不能運行。於是,產生了一個逆向的邪念~
在分析上面提到的小工具之後,發現了其對GPS管理的功能模組,經過簡單的分析之後,發現在Android SDK版本不同的情況下,對GPS控制的代碼還不一樣。首先附上在2.2版本及以前版本的GPS控制碼:
/**
* 實現了一個GPS的開關,當前關閉則開啟,當前開啟則關閉
* 適用版本號碼:
* 1.6 / 2.1 / 2.2
*
* Uri.parse()的參數"custom:3"中的數字3的枚舉值如下:
* private static final int BUTTON_BLUETOOTH = 4;
* private static final int BUTTON_BRIGHTNESS = 1;
* private static final int BUTTON_GPS = 3;
* private static final int BUTTON_SYNC = 2;
* private static final int BUTTON_WIFI = 0;
*
*/
private void toggleGPS() {
// 當SDK版本號碼為2.3以下版本時
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
Intent gpsIntent = new Intent();
gpsIntent.setClassName("com.android.settings",
"com.android.settings.widget.SettingsAppWidgetProvider");
gpsIntent.addCategory("android.intent.category.ALTERNATIVE");
gpsIntent.setData(Uri.parse("custom:3"));
try {
PendingIntent.getBroadcast(this, 0, gpsIntent, 0).send();
} catch (CanceledException e) {
e.printStackTrace();
}
}
}
以上這段代碼,是利用Android平台內建的Widget外掛程式對各種開關進行管理的。實現的是一個GPS的開關,如果當前GPS處於關閉狀態,則將其開啟;如果GPS處於開啟狀態,則將其關閉。
大家可能已經注意到函數體內部的第一行注釋“當SDK版本號碼為2.3一下版本時”,的確我們在這裡做了一個針對SDK版本的判斷。這一個判斷也是我們下一個小節要重點介紹的內容,暫時放在一邊,不要在這一節裡面跑偏了。
在SDK 2.3及之後的版本中,那個小工具利用了SDK中的類Settings.Secure的一個靜態方法:
public static final void setLocationProviderEnabled (ContentResolver cr, String provider, boolean enabled)
Since: API Level 8
Thread-safe method for enabling or disabling a single location provider.
Parameters
cr |
the content resolver to use |
provider |
the location provider to enable or disable |
enabled |
true if the provider should be enabled |
這個方法從API Level 8才開始提供,API Level 8對應的SDK版本是2.2,OK!那按照正常情況來說,這個函數應該是支援SDK2.3的。不妨寫個函數來試試。(這個代碼比較簡單,我就不再貼代碼了)結果卻令人意外,沒有給使用者指派許可權"android.permission.WRITE_SETTINGS";好嘛,那就加上許可權;又提示沒有許可權“android.permission.WRITE_SECURE_SETTINGS”,好說,再加上這個許可權。接下來,見證悲催的時刻到了,還是提示沒有“android.permission.WRITE_SECURE_SETTINGS”的許可權。明明已經加上了許可權,為何還是提示。最後也是在各種大小論壇裡面尋找資料,說是在2.3版本裡面,Google把這個許可權完全鎖住了,好吧,悲劇了,除非你自己改Android代碼,否則就真的沒有別的辦法了。
所以,在第一節結束的時候,提醒各位童鞋,如果想在SDK2.3版本管理GPS,還是乖乖的用你的Intent開啟系統預設的管理GPS的Activity吧。
二、SDK版本對照
為了下載android SDK的源碼,我到處找連結,好不容易一個連結,發現檔案名稱後面怎麼還有一個類似英文名的東西?
的確,像我這樣的初學者,是不知道這個英文單詞代表什麼意思的。但是在逆代碼的過程,發現了Android API給我們提供了這樣個類android.os.Build,在這個類中定義了Android SDK每個版本的版本號碼,版本名,以後其他一些資訊,感興趣的同學可以去開發文檔中看看。
這裡的英文單詞,就是每個SDK版本的版本名稱。
VERSION_CODES
/**
* Enumeration of the currently known SDK version codes. These are the
* values that can be found in {@link VERSION#SDK}. Version numbers
* increment monotonically with each official platform release.
*/
public static class VERSION_CODES {
/**
* Magic version number for a current development build, which has
* not yet turned into an official release.
*/
public static final int CUR_DEVELOPMENT = 10000;
/**
* October 2008: The original, first, version of Android. Yay!
*/
public static final int BASE = 1;
/**
* February 2009: First Android update, officially called 1.1.
*/
public static final int BASE_1_1 = 2;
/**
* May 2009: Android 1.5.
*/
public static final int CUPCAKE = 3;
/**
* September 2009: Android 1.6.
*
* <p>Applications targeting this or a later release will get these
* new changes in behavior:</p>
* <ul>
* <li> They must explicitly request the
* {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission to be
* able to modify the contents of the SD card. (Apps targeting
* earlier versions will always request the permission.)
* <li> They must explicitly request the
* {@link android.Manifest.permission#READ_PHONE_STATE} permission to be
* able to be able to retrieve phone state info. (Apps targeting
* earlier versions will always request the permission.)
* <li> They are assumed to support different screen densities and
* sizes. (Apps targeting earlier versions are assumed to only support
* medium density normal size screens unless otherwise indicated).
* They can still explicitly specify screen support either way with the
* supports-screens manifest tag.
* </ul>
*/
public static final int DONUT = 4;
/**
* November 2009: Android 2.0
*
* <p>Applications targeting this or a later release will get these
* new changes in behavior:</p>
* <ul>
* <li> The {@link android.app.Service#onStartCommand
* Service.onStartCommand} function will return the new
* {@link android.app.Service#START_STICKY} behavior instead of the
* old compatibility {@link android.app.Service#START_STICKY_COMPATIBILITY}.
* <li> The {@link android.app.Activity} class will now execute back
* key presses on the key up instead of key down, to be able to detect
* canceled presses from virtual keys.
* <li> The {@link android.widget.TabWidget} class will use a new color scheme
* for tabs. In the new scheme, the foreground tab has a medium gray background
* the background tabs have a dark gray background.
* </ul>
*/
public static final int ECLAIR = 5;
/**
* December 2009: Android 2.0.1
*/
public static final int ECLAIR_0_1 = 6;
/**
* January 2010: Android 2.1
*/
public static final int ECLAIR_MR1 = 7;
/**
* June 2010: Android 2.2
*/
public static final int FROYO = 8;
/**
* Newest version of Android, version 2.3.
*/
public static final int GINGERBREAD = 9;
}
Android 1.5:Cupcake(杯子蛋糕)
Android 1.6:Donut(甜甜圈)
Android 2.0 / 2.1:Eclair(閃電泡芙)
Android 2.2:Froyo(冷凍憂格)
Android 2.3:Gingerbread(薑餅)
Android 3.0:Honeycomb(蜂巢)
有時候在編碼過程,的確會遇到在不同的SDK版本下,某一個功能的實現方案不一樣的情況,這時就需要大家判斷SDK的版本,採取不同的實現方案,這樣才能讓我們的App保證良好的相容性。所以相信下面這個簡單的判斷語句對你來說,會非常有用:
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
......
}
如果想對這個有一個更加深入的瞭解,建議仔細看看Class android.os.Build,開發文檔始終使我們學習的利器。
希望以上的這些東西對大家會有用!與大家共勉!