Compose也能开发iOS了,快来体验~

news2024/10/5 19:09:29

前言

在之前,我们已经体验了Compose for Desktop 与 Compose for Web,目前Compose for iOS 已经有尚未开放的实验性API,乐观估计今年年底将会发布Compose for iOS。同时Kotlin也表示将在2023年发布KMM的稳定版本。

届时Compose-jb + KMM 将实现Kotlin全平台。

搭建项目

创建项目

因为目前Compose for iOS阶段还在试验阶段,所以我们无法使用Android Studio或者IDEA直接创建Compose支持iOS的项目,这里我们采用之前的方法,先使用Android Studio创建一个KMM项目,如果你不知道如何创建一个KMM项目,可以参照之前的这篇文章KMM的初次尝试~ ,项目目录结构如下所示。

创建好KMM项目后我们需要添加Compose跨平台的相关配置。

添加配置

首先在settings.gradle文件中声明compose插件,代码如下所示:

pluginManagement {
    repositories {
        google()
        gradlePluginPortal()
        mavenCentral()
        maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
    }

    plugins {
        val composeVersion = extra["compose.version"] as String
        id("org.jetbrains.compose").version(composeVersion)
    }
}

这里compose.version的版本号是声明在gradle.properties中的,代码如下所示:

compose.version=1.3.0

然后我们在shared模块中的build文件中引用插件

plugins {
    kotlin("multiplatform")
    kotlin("native.cocoapods")
    id("com.android.library")
    id("org.jetbrains.compose")
}

并为commonMain添加compose依赖,代码如下所示:

val commonMain by getting {
    dependencies {
        implementation(compose.ui)
        implementation(compose.foundation)
        implementation(compose.material)
        implementation(compose.runtime)
    }
}

sync之后,你会发现一个错误警告:uikit还处于试验阶段并且有许多bug....

uikit就是compose-jb暴露的UIKit对象。为了能够使用,我们需要在gradle.properties文件中添加如下配置:

org.jetbrains.compose.experimental.uikit.enabled=true

添加好配置之后,我们先来运行下iOS项目,确保添加的配置是无误的。

果然,不运行不知道,一运行吓一跳

这个问题困扰了我两三天,实在是无从下手,毕竟现在相关的资料很少,经过N次的搜索,最终解决的方案很简单:Kotlin版本升级至1.8.0就可以了。

kotlin("android").version("1.8.0").apply(false)

再次运行项目,结果如下图所示。

不过这是KMM的iOS项目,接下来我们看如何使用Compose编写iOS页面。

开始iOS之旅

我们替换掉iOSApp.swift中的原有代码,替换后的代码如下所示:

import UIKit
import shared

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        window = UIWindow(frame: UIScreen.main.bounds)
        let mainViewController = Main_iosKt.MainViewController()
        window?.rootViewController = mainViewController
        window?.makeKeyAndVisible()
        return true
    }
}

上面的代码看不懂没关系,我们只来看获取mainViewController的这一行

let mainViewController = Main_iosKt.MainViewController()

Main_iosKt.MainViewController是通过新建在shared模块iOSMain目录下的main.ios.kt文件获取的,代码如下所示:

fun MainViewController(): UIViewController =
    Application("Login") {
        //调用一个Compose方法
    }

接下来所有的事情就都可以交给Compose了。

实现一个登录页面

因为页面这部分是公用的,所以我们在shared模块下的commonMain文件夹下新建Login.kt文件,编写一个简单的登录页面,代码如下所示:

@Composable
internal fun login() {
    var userName by remember {
        mutableStateOf("")
    }
    var password by remember {
        mutableStateOf("")
    }
    Surface(modifier = Modifier.padding(30.dp)) {
        Column {
            TextField(userName, onValueChange = {
                userName = it
            }, placeholder = { Text("请输入用户名") })
            TextField(password, onValueChange = {
                password = it
            }, placeholder = { Text("请输入密码") })
            Button(onClick = {
                //登录
            }) {
                Text("登录")
            }
        }
    }
}

上述代码声明了一个用户名输入框、密码输入框和一个登录按钮,就是简单的Compose代码。

然后需要在main.ios.kt中调用这个login方法:

fun MainViewController(): UIViewController =
    Application("Login") {
        login()
    }

运行iOS程序,效果如下图所示:

嗯~,Compose 在iOS上UI几乎可以做到100%复用,还有不学习Compose的理由吗?

实现一个双端网络请求功能

在之前的第1弹和第2弹中,我们分别实现了在Desktop、和Web端的网络请求功能,现在我们对之前的功能在iOS上再次实现。

添加网络请求配置

首先在shared模块下的build文件中添加网络请求相关的配置,这里网络请求我们使用Ktor,具体的可参照之前的文章:KMM的初次尝试~

配置代码如下所示:

val commonMain by getting {
    dependencies {
        ...
        implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
        implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")
        implementation("io.ktor:ktor-client-core:$ktorVersion")
        implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")
        implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")
    }
}
val iosMain by getting {
    dependencies {
        implementation("io.ktor:ktor-client-darwin:$ktorVersion")
    }
}
val androidMain by getting {
    dependencies {
        implementation("io.ktor:ktor-client-android:$ktorVersion")
    }
}

添加接口

这里我们仍然使用「wandroid」中的每日一问接口 :https://wanandroid.com/wenda/list/1/json

DemoReqData与之前系列的实体类是一样的,这里就不重复展示了。

创建接口地址类,代码如下所示。

object Api {
    val dataApi = "https://wanandroid.com/wenda/list/1/json"
}

创建HttpUtil类,用于创建HttpClient对象和获取数据的方法,代码如下所示。

class HttpUtil {
    private val httpClient = HttpClient {
        install(ContentNegotiation) {
            json(Json {
                prettyPrint = true
                isLenient = true
                ignoreUnknownKeys = true
            })
        }
    }

    /**
     * 获取数据
     */
    suspend fun getData(): DemoReqData {
        val rockets: DemoReqData =
            httpClient.get(Api.dataApi).body()
        return rockets
    }
}

这里的代码我们应该都是比较熟悉的,仅仅是换了一个网络请求框架而已。现在公共的业务逻辑已经处理好了,只需要页面端调用方法然后解析数据并展示即可。

编写UI层

由于Android、iOS、Desktop三端的UI都是完全复用的,所以我们将之前实现的UI搬过来即可。代码如下所示:

Column() {
    val scope = rememberCoroutineScope()
    var demoReqData by remember { mutableStateOf(DemoReqData()) }
    Button(onClick = {
        scope.launch {
            try {
                demoReqData = HttpUtil().getData()
            } catch (e: Exception) {
            }
        }
    }) {
        Text(text = "请求数据")
    }
    
    LazyColumn {
        repeat(demoReqData.data?.datas?.size ?: 0) {
            item {
                Message(demoReqData.data?.datas?.get(it))
            }
        }
    }
}

获取数据后,通过

Message方法

将数据展示出来,这里只将作者与标题内容显示出来,代码如下所示。

@Composable
fun Message(data: DemoReqData.DataBean.DatasBean?) {
    Card(
        modifier = Modifier
            .background(Color.White)
            .padding(10.dp)
            .fillMaxWidth(), elevation = 10.dp
    ) {
        Column(modifier = Modifier.padding(10.dp)) {
            Text(
                text = "作者:${data?.author}"
            )
            Text(text = "${data?.title}")
        }
    }
}

分别运行iOS、Android程序,点击请求数据按钮,结果如下图:

这样我们就用一套代码,实现了在双端的网络请求功能。

一个尴尬的问题

我一直认为存在一个比较尴尬的问题,那就是像上面实现一个完整的双端网络请求功能需要用到KMM + Compose-jb,但是KMM与Compose-jb并不是一个东西,但是用的时候呢基本上都是一起用。Compose-jb很久之前已经发了稳定版本只是Compose-iOS目前还没有开放出来,而KMM当前还处于试验阶段,不过在2023年Kotlin的RoadMap中,Kotlin已经表示将会在23年中发布第一个稳定版本的KMM。而Compose for iOS何时发布,我想也是指日可待的事情。

所以,这个系列我觉得改名为:Kotlin跨平台系列更适合一些,要不然以后就会存在KMM跨平台第n弹,Compse跨平台第n弹....

因此,从第四弹开始,此系列将更名为:Kotin跨平台第N弹:~

写在最后

从自身体验来讲,我觉得KMM+Compose-jb 对Android开发者来说是非常友好的,不需要像Flutter那样还需要额外学习Dart语言。所以,你觉得距离Kotlin一统“江山”的日子还会远吗?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/589447.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

腾讯云4核8G服务器12M带宽支持多少人访问?

腾讯云轻量4核8G12M服务器配置446元一年,518元12个月,腾讯云轻量应用服务器具有100%CPU性能,系统盘为180GB SSD盘,12M带宽下载速度1536KB/秒,月流量2000GB,折合每天66.6GB流量,超出月流量包的流…

解锁接口关联测试新技能!HttpRunner教你如何轻松搞定。

目录 前言: 一、安装HttpRunner 二、编写测试用例 三、运行测试用例 四、实现接口关联测试 五、总结 前言: 在接口自动化测试中,一个常见的场景就是需要对多个接口进行关联测试,例如登录后获取token,再利用token…

如何自学黑客?零基础自学黑客需要多久?

问题一:黑客如何学起? 必须从学习者的角度来看,如果你是一个已经学过编程,通晓几门语言的人那么这个答案就会和一个从没有接触过的计算机,甚至连什么叫高级语言还不知道的人有所区别的对待。 这就像是登珠穆朗玛峰一…

ARM实验5-流水灯仿真实验

一、实验名称:流水灯仿真实验 二、实验目的: 掌握ARM处理器的输入输出接口。掌握通过MDK提供的仿真功能,实现系统的仿真运行。通过该编程实验,进一步巩固和强化学生ARM汇编编程的能,ARM应用程序框架,培养…

chatgpt赋能python:Python中的主函数调用其它函数

Python中的主函数调用其它函数 Python语言是一种高级编程语言,它被广泛应用于大数据处理、人工智能、数据分析、网络编程以及Web开发等领域中。在Python中,我们可以使用函数来封装复杂的业务逻辑,使代码更加可读、可维护和可扩展。在本文中&…

基于docker部署testlink并集成mantis

使用docker pull命令拉取需要的镜像。由于testlink和mantis都需要存储相关数据,所以这里可以看到还拉取了一个mysql镜像。 # docker pull bitnami/testlink:1.9.16-r8 # docker pull vimagick/mantisbt # docker pull mysql:5.7.20 使用docker network命令中创建…

Flutter重构开发

最近学习了flutter技术,然后用flutter技术重构了线上项目的首页板块,较深入的理解flutter的状态管理和ui组件的使用,总结下遇到的几点问题。 - 使用gex的controller报错 Don’t use one refreshController to multiple SmartRefresher,It w…

2021年长三角高校数学建模竞赛B题锅炉水冷壁温度曲线解题全过程文档及程序

2021年长三角高校数学建模竞赛 B题 锅炉水冷壁温度曲线 原题再现: 在燃煤发电过程中,锅炉是一种重要的热能动力设备。它通过在炉膛中燃烧煤粉释放热量,将水加热成一定温度(或压力)的蒸汽,蒸汽再推动汽轮机…

C4d渲染农场的定义、应用领域和未来发展趋势

Cinema 4D(C4D)是一款常用于3D动画、建模和渲染的软件,由Maxon Computer开发。随着CG行业的不断发展和应用场景的多样化,C4D渲染农场成为了CG制作中不可或缺的一环。本文将深入介绍C4D渲染农场的概念、特点、应用以及未来发展趋势…

信创办公–基于WPS的EXCEL最佳实践系列 (规整数据摆放)

信创办公–基于WPS的EXCEL最佳实践系列 (规整数据摆放) 目录 应用背景操作步骤1、数据排序2、例如:职务按照 经理-主任-职员 排序3、排列第二种方法4、实操案例5、案例练习一方法一:通过公式函数增加辅助列方法二:用辅…

二分查找笔记

1.1 什么是算法? 定义 在数学和计算机科学领域,算法是一系列有限的严谨指令,通常用于解决一类特定问题或执行计算 In mathematics and computer science, an algorithm (/ˈlɡərɪəm/) is a finite sequence of rigorous instructions, …

IO多路转接之select

本文分享的是IO多路转接中的select,其中包括select函数如何去使用,以及使用相关代码实现客户端向服务端发送消息的服务,从而更好地理解多路转接的select。 多路转接 多路转接是IO模型的一种,这种IO模型通过select函数进行IO等待&…

AI浪潮再掀低代码开发热,快来了解最新趋势!

在近些年的发展中,人工智能 (AI) 已融入我们社会和生活的方方面面。从聊天机器人和虚拟助手到自动化工业机械和自动驾驶汽车,我们已经越来越离不开AI技术了,哪怕是我们的日常生活中也充满了它的影子,我们很难忽视它的影响。 AI时代…

小程序、网页跳转App的原理

从不同的渠道,如小程序、二维码、网页等,直接跳转到App内对应的页面,并传递相关的参数信息,已经由拥有深度链接技术的SDK实现了,App只需接入这类SDK即可获得多样化跳转的功能。本文将详细介绍多样化跳转的原理。 多样…

Unity | HDRP高清渲染管线学习笔记:基本操作

目录 一、场景整体环境光强度 1.HDRI Sky 2.Shadows 二、屏幕后处理效果(Post Processing) 1.Exposure 2.Post-processing/Tonemapping 三、抗锯齿 四、添加光源 1.Light Explorer窗口 2.光照探针组 3.反射探针 4.烘焙光照贴图 本文主要是了解HDRP基本操作&#xf…

高完整性系统:Hoare Logic

目录 1. 霍尔逻辑(Proving Programs Correct) 1.1 警告(Caveats) 1.2 误解(Misconception) 1.3 编程语言(Programming Language) 1.4 程序(Programs) 1…

Html源代码加密?

什么是Html源代码加密? 使用JavaScript加密转化技术将Html变为密文,以此保护html源代码,这便是Html源码加密。 同时,这种加密技术还可实现网页反调试、防复制、链接加密等功能。 应用场景 什么情况下需要Html源代码加密&#x…

clipboard复制粘题问题

clipboard复制粘贴问题 简单的clipboard用法引入clipboard使用方法 通过监听获取剪切板数据自定义获取clipboard剪切板值 记录下项目中使用clipboard复制粘题问题 简单的clipboard用法 引入clipboard npm install clipboard --save官网地址:传送门 使用方法 通过监听获取剪切…

基于neo4图数据库的简易对话系统

文章目录 一、环境二、思路第一步:输入问句第二步:针对问句进行分析,包括意图识别和实体识别第三步:问句转化第四步:问题回答的模板设计 三、代码解读1. 项目结构2. 数据说明3. 主文件kbqa_test.py解读4. entity_extra…

【第三方库】PHP实现创建PDF文件和编辑PDF文件

目录 引入Setasign/fpdf、Setasign/fpdi 解决写入中文时乱码问题 1.下载并放置中文语言包(他人封装):https://github.com/DCgithub21/cd_FPDF 2.编写并运行生成字体文件的程序文件(addFont.php) 中文字体举例&…