AndroidUtilCodeKTX !是時候提高你的開發效率了 !(持續更新中...)

前言

第一次接觸 Kotlin 仍是 2017 年,當時 Kotlin 還沒扶正,也不是 Android 的官方開發語言。至於我是怎麼被安利的,沒記錯的話,應該是 開源實驗室 的 Kotlin 教程。當時身邊幾乎沒有人在學 Kotlin,網上相關的資料也不多,我還翻譯了一部分官網文檔,寫了一本 GitBook 。 固然如今有更好的 Kotlin 語言中文站 了,對於英文基礎不是很好的同窗,這是一個不錯的入門資料。java

兩年半時間過來了,Kotlin 搖身一變,穩坐 Android 官方開發語言。儘管多是爲了不與 Oracle 的訴訟,但我相信這絕對不是主要緣由。被定義爲 Better Java 的 Kotlin,的確作到了更好,也逐漸爲更多人所使用。android

《全新 LeakCanary 2 ! 徹底基於 Kotlin 重構升級 !》git

Retrofit 2.6.0 ! 更快捷的協程體驗 !github

愈來愈多的知名三方庫都已經開始提供對 Kotlin 的支持。Android 官方的新特性也將優先支持 Kotlin。除了 Android 領域,Spring 5 正式發佈時,也將 Kotlin 做爲其主打的新特性之一。肉眼可見的,在 JVM 語言領域,Kotlin 必將有一番做爲。瀏覽器

我在以前的一篇文章 真香!Kotlin+MVVM+LiveData+協程 打造 Wanandroid! 中開源了 Kotlin MVVM 版本的 Wanandroid 應用,到如今一共有 138 個 star 和 20 個 fork。數據並非多亮眼,但算是我開源生涯中的一大步。這個項目我也一直在更新,歡迎你們持續關注。安全

目前的工做中,除非一些不可抗拒因素,我已經將 Kotlin 做爲第一選擇。在進行多個項目的開發工做以後,我發現我常常在各個項目之間拷貝代碼,base 類,擴展函數,工具類等等。甚至有的時候會翻回之前的 Java 代碼,或者 Blankj 的 AndroidUtilCode,拿過來直接使用。可是不少時候直接生搬硬套 Java 工具類,並非那麼的優雅,也沒有很好的運用 Kotlin 語言特性。我迫切須要一個通用的 Kotlin 工具類庫。bash

基於此,AndroidUtilCodeKTX 誕生了。若是你用過 Blankj 的 AndroidUtilCode,它們的性質是同樣的,但毫不是其簡單的 Kotlin 翻譯版本,而是更多的糅合了 Kotlin 特性,一切從 「簡」 ,代碼越少越好。Talk is easy,show me the code ! 話很少說,下面就代碼展現 AndroidUtilCodeKTX 中一些工具類的使用。微信

AndroidUtilCodeKTX

權限請求

request(Manifest.permission.READ_CALENDAR, Manifest.permission.RECORD_AUDIO) {
    onGranted { toast("onGranted") }
    onDenied { toast("onDenied") }
    onShowRationale { showRationale(it) }
    onNeverAskAgain { goToAppInfoPage() }
}
複製代碼

藉助擴展函數和 DSL ,能夠輕鬆的在 Activity 中優雅的請求權限以及處理回調。這不是一個全新的輪子,主要代碼來自 PermissionsKt 。可是它有一個致命的缺點,須要開發者手動覆寫 onRequestPermissionsResult() 來處理權限請求結果,這顯得並非那麼簡潔和優雅。我這裏借鑑了 RxPermissions 的處理方式,經過在當前 Activity 依附一個 Fragment 進行權限請求以及回調處理,這樣對用戶來講是無感的,且避免了額外的代碼。後續會單獨寫一篇文章,分析其中 Kotlin DSL 的應用。app

SharedPreferences

putSpValue("int", 1)
putSpValue("float", 1f)
putSpValue("boolean", true)
putSpValue("string", "ktx")
putSpValue("serialize", Person("Man", 3))

getSpValue("int", 0)
getSpValue("float", 0f)
getSpValue(key = "boolean", default = false)
getSpValue("string", "null")
getSpValue("serialize", Person("default", 0))
複製代碼

基本的存儲和讀取操做都只須要一個函數便可完成,依賴泛型無需主動聲明值的類型。默認存儲文件名稱爲包名,若是你想自定義文件名稱,聲明 name 參數便可:函數

putSpValue("another","from another sp file",name = "another")
getSpValue("another","null",name = "another")
複製代碼

Activity 相關

主要是優化了 startActivity 的使用,爭取作到任何狀況下均可以一句代碼啓動 Activity。

普通跳轉:

startKtxActivity<AnotherActivity>()
複製代碼

帶 flag 跳轉:

startKtxActivity<AnotherActivity>(Intent.FLAG_ACTIVITY_NEW_TASK)
複製代碼

startActivityForResult :

startKtxActivityForResult<AnotherActivity>(requestCode = 1024)
複製代碼

帶值跳轉:

startKtxActivity<AnotherActivity>(value = "string" to "single value")
複製代碼

帶多個值跳轉:

startKtxActivity<AnotherActivity>(
                values = arrayListOf(
                    "int" to 1,
                    "boolean" to true,
                    "string" to "multi value"
                )
            )
複製代碼

帶 Bundle 跳轉:

startKtxActivity<AnotherActivity>(
                extra = Bundle().apply {
                    putInt("int", 2)
                    putBoolean("boolean", true)
                    putString("string", "from bundle")
                }
            )
複製代碼

基本涵蓋了全部的 Activity 跳轉狀況。

Aes 加密相關

ByteArray.aesEncrypt(key: ByteArray, iv: ByteArray, cipherAlgotirhm: String = AES_CFB_NOPADDING): ByteArray
ByteArray.aesDecrypt(key: ByteArray, iv: ByteArray, cipherAlgotirhm: String = AES_CFB_NOPADDING): ByteArray 
File.aesEncrypt(key: ByteArray, iv: ByteArray, destFilePath: String): File?
File.aesDecrypt(key: ByteArray, iv: ByteArray, destFilePath: String): File?
複製代碼

封裝了 Aes 加密操做,提供了快捷的數據和文件加解密方法,無需關注內部細節。默認使用 AES/CFB/NoPadding 模式,你能夠經過 cipherAlgotirhm 參數修改模式。

plainText.toByteArray().aesEncrypt(key, iv, "AES/CBC/PKCS5Padding"
plainText.toByteArray().aesEncrypt(key, iv, "AES/ECB/PKCS5Padding"
plainText.toByteArray().aesEncrypt(key, iv, "AES/CTR/PKCS5Padding"
複製代碼

Hash 相關

StringByteArray 提供了擴展方法,能夠快捷的進行哈希。

ByteArray.hash(algorithm: Hash): String
String.hash(algorithm: Hash, charset: Charset = Charset.forName("utf-8")): String
ByteArray.md5Bytes(): ByteArray
ByteArray.md5(): String
String.md5(charset: Charset = Charset.forName("utf-8")): String
ByteArray.sha1Bytes(): ByteArray
ByteArray.sha1(): String
String.sha1(charset: Charset = Charset.forName("utf-8")): String
ByteArray.sha224Bytes(): ByteArray
ByteArray.sha224(): String
String.sha224(charset: Charset = Charset.forName("utf-8")): String
ByteArray.sha256Bytes(): ByteArray
ByteArray.sha256(): String
String.sha256(charset: Charset = Charset.forName("utf-8")): String
ByteArray.sha384Bytes(): ByteArray
ByteArray.sha384(): String
String.sha384(charset: Charset = Charset.forName("utf-8")): String
ByteArray.sha512Bytes(): ByteArray
ByteArray.sha512(): String
String.sha512(charset: Charset = Charset.forName("utf-8")): String
File.hash(algorithm: Hash = Hash.SHA1): String
複製代碼

支持 MD5, sha1, sha224, sha256, sha384, sha512MD5 已經再也不安全,密碼學上來講已經再也不推薦使用。

val origin = "hello"
val md5 = origin.hash(Hash.MD5)
val sha1 = origin.hash(Hash.SHA1)
複製代碼

除了字符串取哈希,還提供了對文件取哈希值操做。

val file = File("xxx")
val md5 = file.hash(Hash.MD5)
val sha1 = file.hash(Hash.SHA1)
複製代碼

Intent 相關

跳轉到應用信息界面:

Context.goToAppInfoPage(packageName: String = this.packageName)
複製代碼

跳轉到日期和時間頁面:

Context.goToDateAndTimePage()
複製代碼

跳轉到語言設置頁面:

Context.goToLanguagePage()
複製代碼

跳轉到無障礙服務設置頁面:

Context.goToAccessibilitySetting()
複製代碼

瀏覽器打開指定網頁:

Context.openBrowser(url: String)
複製代碼

安裝 apk :

// need android.permission.REQUEST_INSTALL_PACKAGES after N
Context.installApk(apkFile: File)
複製代碼

在應用商店中打開應用:

Context.openInAppStore(packageName: String = this.packageName)
複製代碼

啓動 App :

Context.openApp(packageName: String)
複製代碼

卸載 App :(好像並無什麼用)

Context.uninstallApp(packageName: String)
複製代碼

Log 相關

fun String.logv(tag: String = TAG) = log(LEVEL.V, tag, this)
fun String.logd(tag: String = TAG) = log(LEVEL.D, tag, this)
fun String.logi(tag: String = TAG) = log(LEVEL.I, tag, this)
fun String.logw(tag: String = TAG) = log(LEVEL.W, tag, this)
fun String.loge(tag: String = TAG) = log(LEVEL.E, tag, this)

private fun log(level: LEVEL, tag: String, message: String) {
    when (level) {
        LEVEL.V -> Log.v(tag, message)
        LEVEL.D -> Log.d(tag, message)
        LEVEL.I -> Log.i(tag, message)
        LEVEL.W -> Log.w(tag, message)
        LEVEL.E -> Log.e(tag, message)
    }
}
複製代碼

tag 默認爲 ktx,你也能夠在參數中本身指定。

"abc".logv()
"def".loge(tag = "xxx")
複製代碼

SystemService 相關

原來咱們是這樣獲取系統服務的:

val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
複製代碼

其實也挺簡潔的,可是咱們忘記了 Context.WINDOW_SERVICE 咋辦?經過擴展屬性可讓它更優雅。

val Context.powerManager get() = getSystemService<PowerManager>()

inline fun <reified T> Context.getSystemService(): T? =
    ContextCompat.getSystemService(this, T::class.java)
複製代碼

對於用戶來講,直接使用 powerManager 便可,無需任何額外工做。

已做爲擴展屬性的系統服務以下:

val Context.windowManager
val Context.clipboardManager
val Context.layoutInflater
val Context.activityManager
val Context.powerManager
val Context.alarmManager
val Context.notificationManager
val Context.keyguardManager
val Context.locationManager
val Context.searchManager
val Context.storageManager
val Context.vibrator
val Context.connectivityManager
val Context.wifiManager
val Context.audioManager
val Context.mediaRouter
val Context.telephonyManager
val Context.sensorManager
val Context.subscriptionManager
val Context.carrierConfigManager
val Context.inputMethodManager
val Context.uiModeManager
val Context.downloadManager
val Context.batteryManager
val Context.jobScheduler
複製代碼

App 相關

Context.versionName: String
Context.versionCode: Long
Context.getAppInfo(apkPath: String): AppInfo
Context.getAppInfos(apkFolderPath: String): List<AppInfo>
Context.getAppSignature(packageName: String = this.packageName): ByteArray?
複製代碼

這一塊內容暫時還比較少,主要是整理了我在項目中遇到的一些常見需求。獲取版本號,版本名稱,根據 apk 文件獲取應用信息,獲取應用簽名等等。App 相關的其實會有不少工具類,後續會慢慢補充。

View 相關

View.visible()
View.invisible()
View.gone()
var View.isVisible: Boolean
var View.isInvisible: Boolean
var View.isGone: Boolean
View.setPadding(@Px size: Int)
View.postDelayed(delayInMillis: Long, crossinline action: () -> Unit): Runnable
View.toBitmap(config: Bitmap.Config = Bitmap.Config.ARGB_8888): Bitmap
複製代碼

也都是一些比較經常使用的函數。

Common

Context.dp2px(dp: Float): Int
Context.px2dp(px: Float): Int
View.dp2px(dp: Float): Int
View.px2dp(px: Float): Int
Context.screenWidth
Context.screenHeight
Context.copyToClipboard(label: String, text: String)
複製代碼

其餘

RecyclerView.itemPadding(top: Int, bottom: Int, left: Int = 0, right: Int = 0)
ByteArray.toHexString(): String
...... 
複製代碼

使用

implementation 'luyao.util.ktx:AndroidUtilKTX:0.0.5'
複製代碼

總結

以上都是我在項目中提煉出來的,也正因如此,如今的 AndroidUtilCodeKTX 還只是個孩子,作不到那麼的盡善盡美,面面俱到。我會持續更新完善這個庫,也但願你們能夠多多提 issuepr,提供您寶貴的意見!

在這裏也十分感謝 Jie Smart 昨天的郵件反饋,提供了一些修改意見,也讓我更有動力去繼續維護。另外,最新版本的 AndroidUtilCodeKTX 我都會第一時間用在個人開源項目 wanandroid 上,歡迎你們 star ,fork !

文章首發微信公衆號: 秉心說 , 專一 Java 、 Android 原創知識分享,LeetCode 題解。

更多相關知識,掃碼關注我吧!

相關文章
相關標籤/搜索