JetBrains开发者日见闻(一)之Kotlin/Native 尝鲜篇

简述: 今天咱们来说点Kotlin中比较时髦的东西,有的人可能会说:“不像你以前的风格啊,以前的文章不是一直在死扣语法以及语法糖背后秘密。当你还在死扣泛型语法的时候,别人的文章早就说了Kotlin/Native和Kotlin1.3的新特性”。瞬间感受本身out了,今天咱们就说说这些时髦的东西,也许你能看到一些和别人不同的东西哦。前端

前段时间大家的熊猫小哥哥(也就是我),因为对Kotlin过分热爱,一天偶然看到2018 JetBrains开发者日-Kotlin专场活动,脑壳一热,瞬间心动了,立刻就买了门票和火车票去北京(第一次一我的去北京)参加活动了。由于看到有Kotlin中文社区两位大佬(这两位大佬是我一年多之前开始写Kotlin的时候就关注了他们)的演讲日程以及JetBrains资深布道师Hali的演讲,没有过多思考直接买票,不要怂就是干。最后顺便和Kotlin社区的大佬们面个基啥的,谢谢大佬们的热情款待。这次北京之行收获挺多的,有时候知道一些最新技术方向和动态会比你埋头闭门造车好的不少。ios

由于在个人公众号上(Kotlin开发者联盟),有一些小伙伴但愿我能从北京的开发者会上带点东西回来,因此总结了一下结合本身实际的开发,给你们带来如下几篇文章。git

  • 一、Kotlin/Native1.0 Beta(尝鲜篇)
  • 二、Kotlin中1.3版本新特性都有哪些?
  • 三、Kotlin中的Coroutine(协程)在Android上应用(协程学前班篇)
  • 四、Ktor异步框架初体验(Ktor学前班篇)

那么,今天就开始第一篇,看过一些大佬写关于Kotlin/ Native的文章,基本上都是翻译了Kotlin Blog的官网博客, 具体如何实践的仍是比较少的。今天我不打算这么讲,既然今天的主题是时髦那就讲点有意思的东西。一块儿来看下今天提纲:程序员

1、从新认识Kotlin语言

在开始以前,我以为有必要一块儿从新来认识一下Kotlin这门语言,不少人一直都认为它不就是门JVM语言和Java、Scala同样都是跑在JVM虚拟机上。其实Kotlin并不只仅是一门JVM语言,它的野心是真的大,JVM语言已经没法知足它的雄心壮志了。它是一门多平台的静态编译型语言,它能够用于JVM上(只不过在JVM层面比较出名而已,致使不少人都认为它是门JVM语言),实则它能够编译成JavaScipt运行在浏览器中也能够编译成IOS的可运行文件跑在LLVM上github

2、Kotlin/Native的基本介绍

用官方的话来讲Kotlin / Native是一种将Kotlin代码编译为本机二进制文件的技术,能够在没有虚拟机的状况下运行。它是基于LLVM的后端,用于Kotlin编译器和Kotlin标准库的本机实现shell

Kotlin/Native目前支持如下平台:编程

  • --- iOS (arm32, arm64, emulator x86_64)
  • --- MacOS (x86_64)
  • --- Android (arm32, arm64)
  • --- Windows (mingw x86_64)
  • --- Linux (x86_64, arm32, MIPS, MIPS little endian)
  • --- WebAssembly (wasm32)

为了更好说明Kotlin/Native能力,下面给出张官方的Kotlin/Native能力图:swift

对于Kotlin/Native以前一直没有去玩过,只是常常听到社区小伙伴们说编译起来巨慢,感受好时髦啊。抱着好奇心,而且也符合咱们这篇文章时髦的主题,决定一步步带你们玩一玩。后端

3、Kotlin/Native开发IOS HelloWorld

一、须要准备的开发工具

  • AppCode 2018.1(建议下载最新版本,这里不是最新版本不过也能玩哈,最新版本应该到了2018.3)
  • Kotlin/Native Plugin 181.5087.34(注意: 插件和AppCode IDE的版本匹配问题,建议把IDE安装好,而后IDE搜索下载会默认给最佳匹配的插件版本的)
  • Xcode 9.2(注意: 这里Xcode版本须要AppCode版本匹配,不然会有问题的,不过不匹配的话IDE会有提示的,建议若是AppCode 2018.1(Xcode 9.2), AppCode 2018.3(Xcode 10.0))

二、建立一个Kotlin/Native项目

第一步: 选择左侧的Kotlin/Native, 并选择右侧的Sing View App with a Kotlin/Native Framework浏览器

第二步: 填写项目名和包名,选择语言Swift(这里先以Swift为例)

第三步: 最后finish便可建立完毕Kotlin/Native项目,建立完毕后项目结构以下

四、运行Kotlin/Native项目

若是你比较幸运跑起来的话,效果应该是在模拟器装一个APP而且起了一个空白页,终端上输出了"Hello from Kotlin!"的Log,相似这样:

注意: 可是你是真题测试,并且Run顶部默认只有一个IOS Device选项的话,而后你又点了Run 说明并且会报以下错误

这个问题是由于默认IOS Device选项是表示用真机调试哈,而后这边就须要一个IOS开发者帐号。设置开发者帐号的话,建议使用Xcode去打开该项目而后给该项目配置一个开发者帐号。

设置完毕Xcode后,AppCode会自动检测到刷新的。

4、Kotlin/Native开发IOS 运行原理分析

看到上面IOS HelloWorld项目运行起来,你们有没有思考一个问题,Kotlin的代码的代码是怎么在IOS设备上跑起来呢?

实际上,在这背后使用了一些脚本和工具在默默支撑着整个项目的运行,如前所述,Kotlin / Native平台有本身的编译器,但每次想要构建项目时手动运行它明显不是高效的。 因此Kotlin团队了选择Gradle。Kotlin / Native使用Gradle构建工具在Xcode中自动完成Kotlin / Native的整个构建过程。在这里使用Gradle意味着开发人员能够利用其内部增量构建架构,只需构建和下载所需内容,从而节省开发人员的宝贵时间。

若是,你还对上述有点疑问不妨一块儿来研究下Kotlin/Native项目中的构建参数脚本:

  • 打开构建脚本是须要在Xcode中打开的,具体能够参考以下图:

经过以上项目能够分析到在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')
}
        

复制代码

5、Kotlin/Native项目结构分析

一、Kotlin/Native + Swift项目结构分析

咱们知道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一遍,效果以下:

二、Kotlin/Native + Objective C项目结构分析

在IOS同事帮助下,进一步了解IOS APP启动基本知识,这将有助于咱们接下来改造咱们项目结构,使得它更加简单,彻底能够删除额外的Swift代码,包括APP启动代理那块都交由Kotlin来完成。

  • 第一步: 先建立一个Kotlin/Native + OC 的项目,这里就不重复建立过程,直接把OC目录结构给出:

  • 第二步: 能够看到OC与Swift项目结构差很少哈,能够看到其中有几个重要的文件,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类
    }

}
复制代码
  • 第三步: 而后转到AppDelegate.m,能够看到在didFinishLaunchingWithOptions函数中调用了KNFKotlinNativeFramework中的helloFromKotlin函数。
- (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/Native + Kotlin项目结构分析

到这里不少人就会问了,看你上面说了那么并无看到你Kotlin在作什么事,全是Swift和OC在作APP启动。如今就是告诉你Kotlin如何去替代它们作APP启动的事了。

  • 先新建立一个项目,此次建立的再也不是Sing View App with a Kotlin/Native Framework, 而是一个Application项目。

  • 生成后的目录文件全是Kotlin文件,具体以下:

  • 生成的main.kt替代main.m,并设置对应启动的AppDelegate
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
        }
    }
}
复制代码
  • 生成AppDelegate替代原来的AppDelegate.m,而且在内部设置好启动的Window.
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)会报错
}
复制代码
  • 再生成一个ViewController,这个ViewController很相似Android中的Activity。
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}!'"
    }
}
复制代码

运行出来的效果以下:

6、Kotlin/Native开发一个地图Demo

一、IOS项目ViewController与组件绑定过程分析

看到上面的运行Demo,你们有没有在思考一个问题IOS项目中的ViewController是怎么和UI组件绑定在一块儿的呢?我我的认为这个很重要,换句话说这就是IOS开发最基本的套路,若是这个都不弄明白的话,下面Demo开发就是云里雾里了,掌握了这个基本套路的话,做为一个Android开发者,你基本上就能够在IOS项目开发中任意折腾了。

  • 第一步: 在kotlin目录下新建一个KNMapViewController类,而且它去继承UIViewController以及实现MKMapViewDelegateProtocol接口,并重写viewDidLoad()函数。而且在viewDidLoad函数实现map地图基本配置。
//导入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)
        }
    }
}
复制代码
  • 第二步: 用Xcode打开项目中的Main.storyboard,删除原来自动生成一些视图组件(若是你处于AppCode中开发项目,实际上直接在AppCode中双击Main.storyboard就会自动使用Xcode打开当前整个项目,并打开这个项目)

  • 第三步: 给当前空的视图绑定对应ViewController,这里是KNMapViewController

  • 第四步: 在当前空的视图中添加一个map view组件而且设置组件的约束条件。

  • 第五步: 右击组件MKMapView能够看到黑色对话框,里面Referencing Outlets还空的,说明当前ViewController没有和MKMapView组件绑定

  • 第六步: 配置outlet,这里说下AppCode很坑爹地方,须要手动去source code中手动配置outlet,选中main.storyboard右击open as 而后选择打开source code

  • 第七步: 在view和viewController结尾标签之间配置connection
    配置的code以下:
<connections>
   <outlet property="mMapView" destination="dest id" id="generate id"/>
</connections>
<!--property属性值就是KNMapViewController中的mMapView变量名;destination属性值是一个map view标签中id(能够在subviews标签内的mapView标签中找到id), id属性则是自动生成的,能够按照格式本身之指定一个,只要不出现重复的id便可-->
复制代码

配置结果以下:

  • 第八步: 检验是否绑定成功, 回到main.stroyboard视图,右击组件查看黑色框是否出现以下绑定关系,出现了则说明配置成功。

二、接着上述配置步骤,就能够回到AppCode中运行项目了

以上的运行结果就说明了,咱们Demo已经运行成功了。而且我已经把这次Kotlin/Native项目都放到了GitHub上,若是感兴趣的小伙伴能够clone下来玩一玩这个时髦的鬼东西。若是以为对你有帮助,还请大佬们给个star。

Kotlin/Native Demo GitHub

7、Kotlin/Native开发体验分析

Kotlin/Native目前仍是处于1.0的beta,因此仍是有不少的地方是不让人满意的。下面我总结此次Kotlin/Native开发体验的优缺点:

优势:

经过上述的几个例子,能够明显代表Kotlin/Native语言层面跨平台能力仍是很强的,和OC,Swfit项目操做性也很强,该有的基本上都已经实现了,因此对于它后续发展仍是很是值得关注的。据我了解到,Kotlin团队目前首要重心就是在Kotlin/Native这一块,但愿他们能给咱们带来更多关于Kotlin/Native的惊喜。

缺点

缺点仍是有不少的:

  • 一、Kotlin/Native编译速度有点慢的惊人,不过运行速度仍是不错的。
  • 二、AppCode中用Kotlin开发IOS项目,没有很强的代码提示,不少API导包都比较麻烦,对于初学者更是一脸懵逼。
  • 三、AppCode中的Kotlin/Native插件竟然没提供右键建立Kotlin类、接口之类,包括官方也给出这是个问题不过提供一个fix方案。

最后能够测试一下:

  • 四、AppCode中使用Kotlin开发IOS项目,配置outlet还得切换到在Xcode手工操做,但愿后续改进。
  • 五、AppCode耗内存还大了,比AndroidStudio还厉害,多开了两个项目,基本就是每操做IDE就在转圈圈,但愿后续改进。

8、聊点关于Kotlin/Native和Flutter框架那点事

一、简述:

其实关于这个主题,我是不太想去说的,由于我不想引发编程语言界的口战。可是总有人喜欢去把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国外技术文章。若是你也喜欢Kotlin,欢迎加入咱们~~~

相关文章
相关标签/搜索