簡述: 今天咱們來說點Kotlin中比較時髦的東西,有的人可能會說:「不像你以前的風格啊,以前的文章不是一直在死扣語法以及語法糖背後祕密。當你還在死扣泛型語法的時候,別人的文章早就說了Kotlin/Native和Kotlin1.3的新特性」。瞬間感受本身out了,今天咱們就說說這些時髦的東西,也許你能看到一些和別人不同的東西哦。前端
前段時間大家的熊貓小哥哥(也就是我),因爲對Kotlin過分熱愛,一天偶然看到2018 JetBrains開發者日-Kotlin專場活動,腦殼一熱,瞬間心動了,立刻就買了門票和火車票去北京(第一次一我的去北京)參加活動了。由於看到有Kotlin中文社區兩位大佬(這兩位大佬是我一年多之前開始寫Kotlin的時候就關注了他們)的演講日程以及JetBrains資深佈道師Hali的演講,沒有過多思考直接買票,不要慫就是幹。最後順便和Kotlin社區的大佬們面個基啥的,謝謝大佬們的熱情款待。這次北京之行收穫挺多的,有時候知道一些最新技術方向和動態會比你埋頭閉門造車好的不少。ios
由於在個人公衆號上(Kotlin開發者聯盟),有一些小夥伴但願我能從北京的開發者會上帶點東西回來,因此總結了一下結合本身實際的開發,給你們帶來如下幾篇文章。git
那麼,今天就開始第一篇,看過一些大佬寫關於Kotlin/ Native的文章,基本上都是翻譯了Kotlin Blog的官網博客, 具體如何實踐的仍是比較少的。今天我不打算這麼講,既然今天的主題是時髦那就講點有意思的東西。一塊兒來看下今天提綱:程序員
在開始以前,我以爲有必要一塊兒從新來認識一下Kotlin這門語言,不少人一直都認爲它不就是門JVM語言和Java、Scala同樣都是跑在JVM虛擬機上。其實Kotlin並不只僅是一門JVM語言,它的野心是真的大,JVM語言已經沒法知足它的雄心壯志了。它是一門多平臺的靜態編譯型語言,它能夠用於JVM上(只不過在JVM層面比較出名而已,致使不少人都認爲它是門JVM語言),實則它能夠編譯成JavaScipt運行在瀏覽器中也能夠編譯成IOS的可運行文件跑在LLVM上github
用官方的話來講Kotlin / Native是一種將Kotlin代碼編譯爲本機二進制文件的技術,能夠在沒有虛擬機的狀況下運行。它是基於LLVM的後端,用於Kotlin編譯器和Kotlin標準庫的本機實現。shell
Kotlin/Native目前支持如下平臺:編程
爲了更好說明Kotlin/Native能力,下面給出張官方的Kotlin/Native能力圖:swift
對於Kotlin/Native以前一直沒有去玩過,只是常常聽到社區小夥伴們說編譯起來巨慢,感受好時髦啊。抱着好奇心,而且也符合咱們這篇文章時髦的主題,決定一步步帶你們玩一玩。後端
第一步: 選擇左側的Kotlin/Native, 並選擇右側的Sing View App with a Kotlin/Native Framework瀏覽器
第二步: 填寫項目名和包名,選擇語言Swift(這裏先以Swift爲例)
第三步: 最後finish便可建立完畢Kotlin/Native項目,建立完畢後項目結構以下
若是你比較幸運跑起來的話,效果應該是在模擬器裝一個APP而且起了一個空白頁,終端上輸出了"Hello from Kotlin!"的Log,相似這樣:
注意: 可是你是真題測試,並且Run頂部默認只有一個IOS Device選項的話,而後你又點了Run 說明並且會報以下錯誤
這個問題是由於默認IOS Device選項是表示用真機調試哈,而後這邊就須要一個IOS開發者帳號。設置開發者帳號的話,建議使用Xcode去打開該項目而後給該項目配置一個開發者帳號。
設置完畢Xcode後,AppCode會自動檢測到刷新的。
看到上面IOS HelloWorld項目運行起來,你們有沒有思考一個問題,Kotlin的代碼的代碼是怎麼在IOS設備上跑起來呢?
實際上,在這背後使用了一些腳本和工具在默默支撐着整個項目的運行,如前所述,Kotlin / Native平臺有本身的編譯器,但每次想要構建項目時手動運行它明顯不是高效的。 因此Kotlin團隊了選擇Gradle。Kotlin / Native使用Gradle構建工具在Xcode中自動完成Kotlin / Native的整個構建過程。在這裏使用Gradle意味着開發人員能夠利用其內部增量構建架構,只需構建和下載所需內容,從而節省開發人員的寶貴時間。
若是,你還對上述有點疑問不妨一塊兒來研究下Kotlin/Native項目中的構建參數腳本:
經過以上項目能夠分析到在Xcode中編譯一個Kotlin/Native項目,實際上在執行一段shell腳本,並在shell腳本執行中gradlew命令來對Kotlin/Native編譯,該腳本調用gradlew工具,該工具是Gradle Build System的一部分,並傳遞構建環境和調試選項。 而後調用一個konan gradle插件實現項目編譯並輸出xxx.kexe文件,最後並把它複製到iOS項目構建目錄("$TARGET_BUILD_DIR/$EXECUTABLE_PATH"
)。
最後來看下Supporting Files中的build.gradle構建文件,裏面就引入了konan插件(Kotlin/Native編譯插件), 有空的話建議能夠深刻研究下konan插件,這裏其實也是比較淺顯分析了下整個編譯過程,若是深刻研究konan插件源碼的話,更能透過現象看到Kotlin/Native本質,這點纔是最重要的。
buildscript {
ext.kotlin_version = '1.2.0'
repositories {
mavenCentral()
maven {
url "https://dl.bintray.com/jetbrains/kotlin-native-dependencies"
}
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-native-gradle-plugin:0.7"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'kotlin'
repositories {
mavenCentral()
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib"
}
apply plugin: 'konan'
konan.targets = [
'ios_arm64', 'ios_x64'
]
konanArtifacts {
program('KotlinNativeOC')
}
複製代碼
咱們知道main函數是不少應用程序的入口,ios也不例外,在AppDelegate.swift中有@UIApplicationMain的註解,這裏就是APP啓動的入口。
@UIApplicationMain //main函數註解入口,因此AppDelegate類至關於啓動入口類
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?//默認加了UIWindow
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// KNFKotlinNativeFramework class is located in the framework that is generated during build.
// If it is not resolved, try building for the device (not simulator) and reopening the project
NSLog("%@", KNFKotlinNativeFramework().helloFromKotlin())//注意: 這裏就是調用了Kotlin中的一個helloFromKotlin方法,並把返回值用Log打印出來,因此你會看到App啓動的時候是有一段Log被打印出來
return true
}
...
}
複製代碼
KotlinNativeFramework類
class KotlinNativeFramework {
fun helloFromKotlin() = "Hello from Kotlin!" //返回一個Hello from Kotlin!字符串
}
複製代碼
可是呢,有追求的程序員絕對不能容許跑出來的是一個空白頁面,空白頁面那還怎麼裝逼呢? 哈哈。在ViewController.swift中的viewDidLoad函數中加入一個文本(UILabel)。
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 300, height: 21))
label.center = CGPoint(x: 160, y: 285)
label.textAlignment = .center
label.font = label.font.withSize(15)
label.text = "Hello IOS, I'm from Kotlin/Native"
view.addSubview(label)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
複製代碼
最後從新run一遍,效果以下:
在IOS同事幫助下,進一步瞭解IOS APP啓動基本知識,這將有助於咱們接下來改造咱們項目結構,使得它更加簡單,徹底能夠刪除額外的Swift代碼,包括APP啓動代理那塊都交由Kotlin來完成。
main.m、AppDelegate.m、ViewController.m
main.m APP啓動入口,至關於main函數,先從main函數入手,而後一步步弄清整個啓動流程。#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));//這裏也調用了AppDelegate類
}
}
複製代碼
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// KNFKotlinNativeFramework class is located in the framework that is generated during build.
// If it is not resolved, try building for the device (not simulator) and reopening the project
NSLog(@"%@", [[[KNFKotlinNativeFramework alloc] init] helloFromKotlin]);//注意這裏調用helloFromKotlin,並輸出日誌
return YES;
}
複製代碼
到這裏不少人就會問了,看你上面說了那麼並無看到你Kotlin在作什麼事,全是Swift和OC在作APP啓動。如今就是告訴你Kotlin如何去替代它們作APP啓動的事了。
import kotlinx.cinterop.autoreleasepool
import kotlinx.cinterop.cstr
import kotlinx.cinterop.memScoped
import kotlinx.cinterop.toCValues
import platform.Foundation.NSStringFromClass
import platform.UIKit.UIApplicationMain
fun main(args: Array<String>) {
memScoped {
val argc = args.size + 1
val argv = (arrayOf("konan") + args).map { it.cstr.getPointer(memScope) }.toCValues()
autoreleasepool {
UIApplicationMain(argc, argv, null, NSStringFromClass(AppDelegate))//注意: 在這裏設置對應啓動的AppDelegate
}
}
}
複製代碼
import kotlinx.cinterop.initBy
import platform.Foundation.NSLog
import platform.UIKit.*
class AppDelegate : UIResponder(), UIApplicationDelegateProtocol {
override fun init() = initBy(AppDelegate())
private var _window: UIWindow? = null
override fun window() = _window
override fun setWindow(window: UIWindow?) { _window = window }
override fun application(application: UIApplication, didFinishLaunchingWithOptions: Map<Any?, *>?): Boolean {//監聽APP啓動完成,打印Log
NSLog("this is launch from kotlin appDelegate")
return true
}
companion object : UIResponderMeta(), UIApplicationDelegateProtocolMeta//注意:必定得有個companion object不然在main函數NSStringFromClass(AppDelegate)會報錯
}
複製代碼
import kotlinx.cinterop.*
import platform.Foundation.*
import platform.UIKit.*
@ExportObjCClass
class ViewController : UIViewController {
constructor(aDecoder: NSCoder) : super(aDecoder)
override fun initWithCoder(aDecoder: NSCoder) = initBy(ViewController(aDecoder))
@ObjCOutlet
lateinit var label: UILabel
@ObjCOutlet
lateinit var textField: UITextField
@ObjCOutlet
lateinit var button: UIButton
@ObjCAction
fun buttonPressed() {
label.text = "Konan says: 'Hello, ${textField.text}!'"
}
}
複製代碼
運行出來的效果以下:
看到上面的運行Demo,你們有沒有在思考一個問題IOS項目中的ViewController是怎麼和UI組件綁定在一塊兒的呢?我我的認爲這個很重要,換句話說這就是IOS開發最基本的套路,若是這個都不弄明白的話,下面Demo開發就是雲裏霧裏了,掌握了這個基本套路的話,做爲一個Android開發者,你基本上就能夠在IOS項目開發中任意折騰了。
//導入Kotlin以與Objective-C和一些Cocoa Touch框架互操做。
import kotlinx.cinterop.*
import platform.CoreLocation.CLLocationCoordinate2DMake
import platform.Foundation.*
import platform.MapKit.MKCoordinateRegionMake
import platform.MapKit.MKCoordinateSpanMake
import platform.MapKit.MKMapView
import platform.MapKit.MKMapViewDelegateProtocol
import platform.UIKit.*
@ExportObjCClass//注意: @ExportObjCClass註解有助於Kotlin建立一個在運行時可查找的類。
class KNMapViewController: UIViewController, MKMapViewDelegateProtocol {
@ObjCOutlet //注意: @ObjCOutlet註解很重要,主要是將mMapView屬性設置爲outlet。這容許您將Main.storyboard中的MKMapview連接到此屬性。
lateinit var mMapView: MKMapView
constructor(aDecoder: NSCoder) : super(aDecoder)
override fun initWithCoder(aDecoder: NSCoder) = initBy(KNMapViewController(aDecoder))
override fun viewDidLoad() {
super.viewDidLoad()
val center = CLLocationCoordinate2DMake(32.07, 118.78)
val span = MKCoordinateSpanMake(0.7, 0.7)
val region = MKCoordinateRegionMake(center, span)
with(mMapView) {
delegate = this@KNMapViewController
setRegion(region, true)
}
}
}
複製代碼
第五步: 右擊組件MKMapView能夠看到黑色對話框,裏面Referencing Outlets還空的,說明當前ViewController沒有和MKMapView組件綁定
第六步: 配置outlet,這裏說下AppCode很坑爹地方,須要手動去source code中手動配置outlet,選中main.storyboard右擊open as 而後選擇打開source code
<connections>
<outlet property="mMapView" destination="dest id" id="generate id"/>
</connections>
<!--property屬性值就是KNMapViewController中的mMapView變量名;destination屬性值是一個map view標籤中id(能夠在subviews標籤內的mapView標籤中找到id), id屬性則是自動生成的,能夠按照格式本身之指定一個,只要不出現重複的id便可-->
複製代碼
配置結果以下:
Kotlin/Native目前仍是處於1.0的beta,因此仍是有不少的地方是不讓人滿意的。下面我總結此次Kotlin/Native開發體驗的優缺點:
經過上述的幾個例子,能夠明顯代表Kotlin/Native語言層面跨平臺能力仍是很強的,和OC,Swfit項目操做性也很強,該有的基本上都已經實現了,因此對於它後續發展仍是很是值得關注的。據我瞭解到,Kotlin團隊目前首要重心就是在Kotlin/Native這一塊,但願他們能給咱們帶來更多關於Kotlin/Native的驚喜。
缺點仍是有不少的:
最後能夠測試一下:
其實關於這個主題,我是不太想去說的,由於我不想引發編程語言界的口戰。可是總有人喜歡去把Kotlin/Native和Flutter放在一塊兒去作對比,由於他們好像都有一個共同點就是跨平臺都能開發Android、IOS應用。而且在這次Jetbrains開發者日上就有參會嘉賓在會上問官方佈道師Hali,Kotlin/Native和Flutter有什麼不同,優點在哪?
針對這個問題我說下我的的觀點:
首先,我我的是很是看好Flutter這個移動端跨平臺框架,它可以徹底抹平Android,IOS API層面的差別性。換句話說就是一個小白,也許他不懂Java,OC或Swift,他只要熟悉dart而且熟悉Flutter框架API就能開發出Android和IOS兩個原生般體驗的應用。確實很爽啊,不管站在公司節約人力和維護成本仍是開發者技術成本角度考慮都是不錯的選擇。但是從另外一角度能夠想象下一旦造成這樣的局面,不少新項目都是用dart開發,swift和oc語言對於新的開發者而言你會去用嗎? 蘋果爸爸貌似就會不開心了,這其中故事你們能夠本身去想像了(固然也許將來不是我說的那樣發展,純屬我的猜測的哈)。
而後,我說下Kotlin/Native吧,其實Kotlin/Native和Flutter不是一個層面東西,不太很好作對比,Kotlin/Native更多的是語言編譯器層面,而Flutter是框架層面。二者根本就不是一個世界的。Flutter是本身實現一套渲染機制和UI引擎,而且有着豐富Development API。而Kotlin/Native更多關注是編譯器如何將kt源碼編譯成IOS LLVM可運行的二進制碼,可是Kotlin/Native並無像Flutter同樣在API層面抹平平臺差別性,而是 在語言層面作了平臺差別性抹平。也就是說你要開發IOS應用不只會Kotlin/Native還得會IOS 應用開發Development Api. 這貌似Kotlin/Native稍遜Flutter一籌,可是想一想也有道理,API層面抹平不是在語言層面職責,仍是須要框架層面來作到這一點,說不定哪天Kotlin團隊也造出一個相似Flutter的輪子呢。並且語言層面跨平臺帶來的還有一點好處就是共享代碼,Android、IOS、前端均可以用Kotlin來實現,能夠把它們擁有相同邏輯用Kotlin編寫的代碼放入一個common包中統一管理,而且Kotlin對多平臺共享這塊作了很好的支持,而後來自於不一樣平臺能夠共享這塊通用的邏輯實現,不用各自平臺去寫一套了。
經過上述觀點,咱們總結到對於開發者而言,學習一門新的技術實際上通常會存在兩層隱造成本。一層是對新的開發語言的掌握,另外一層則是對這門技術的Development Api的熟悉和掌握。那麼Kotlin/Native就是爲了磨平第一層開發語言的障礙。語言層面能作的也只能這樣了,不像Flutter它是一個框架,它能夠直接從API層面抹平。若是Flutter最終能推廣起來,在熱更新和熱修復這塊支持比如今的原生還好的話,而且你是一個初學者,那麼它絕對是一個不錯的選擇。
若是你是Kotlin開發者,你徹底可使用Kotlin/Native而後花一些時間熟悉下IOS的API也能把IOS應用玩起來。固然Kotlin/Native開發IOS應用只是其中一小部分,你徹底用它去作更多有意義的事。
若是你是移動開發者,建議兩門技術均可以去嘗試一下畢竟技多不壓身,固然語言只是一門工具,最終靠仍是計算機紮實的基礎、分析需求的能力以及架構項目的功能能力。有了這些能力再加上一個高效的編程語言那麼你就更加所向披靡了。
原創系列:
翻譯系列:
實戰系列:
歡迎關注Kotlin開發者聯盟,這裏有最新Kotlin技術文章,每週會不按期翻譯一篇Kotlin國外技術文章。若是你也喜歡Kotlin,歡迎加入咱們~~~