当前位置: 首页 > news >正文

【Compose multiplatform教程】05 IOS环境编译

 了解如何使现有的 Android 应用程序跨平台,以便它在 Android 和 iOS 上都能运行。您将能够在一个位置编写代码并针对 Android 和 iOS 进行测试一次。

本教程使用一个示例 Android 应用程序,其中包含用于输入用户名和密码的单个屏幕。凭证经过验证并保存到“内存”数据库。

如果您不熟悉 Kotlin Multiplatform,请先了解如何设置环境并从头开始创建跨平台应用程序。

Window开发环境

编译Ios环境需要mac xcode,如果您是window

需要安装虚拟机,虚拟机有许多种,这里仅介绍

VMware安装macOS虚拟机详细教程icon-default.png?t=O83Ahttps://www.overwall.info/168.html

vmware虚拟机安装macOS视频教程icon-default.png?t=O83Ahttps://www.bilibili.com/video/BV1PtynYHE13/?spm_id_from=333.337.search-card.all.click&vd_source=36df3adcf294146e4c45aa1b10354537

准备开发环境

  1. 安装所有必要的工具并将它们更新到最新版本icon-default.png?t=O83Ahttps://www.jetbrains.com/help/kotlin-multiplatform-dev/multiplatform-setup.html

您需要一台装有 macOS 的 Mac 才能完成本教程中的某些步骤,其中包括编写特定于 iOS 的代码和运行 iOS 应用程序。这些步骤不能在其他操作系统上执行,例如 Microsoft Windows。这是由于 Apple 的要求。 

让你的跨平台应用在 iOS 上运行

一旦你使安卓应用具备跨平台特性,就可以创建一个 iOS 应用,并复用其中共享的业务逻辑。

1.在 Xcode 中创建一个 iOS 项目。
2.将框架连接到你的 iOS 项目。
3.从 Swift 使用共享模块。

在 Xcode 中创建 iOS 项目


1.在 Xcode 中,点击 “文件”|“新建”|“项目”。
2.选择一个 iOS 应用模板,然后点击 “下一步”。

3.将产品名称设定为 “simpleLoginIOS” ,然后点击 “下一步”。

4.对于项目的存储位置,选择存放你跨平台应用的目录,比如 “kmp - integration - sample”。

在安卓开发工具(Android Studio)中,你会得到以下结构:

为了与跨平台项目的其他顶级目录保持一致,你可以将 “simpleLoginIOS” 目录重命名为 “iosApp”。要完成这一操作,需先关闭 Xcode,然后把 “simpleLoginIOS” 目录重命名为 “iosApp”。要是在 Xcode 打开的状态下重命名该文件夹,你将会收到警告,而且还有可能损坏项目。

将框架连接到你的 iOS 项目

一旦你有了框架,就可以手动将其连接到你的 iOS 项目中。

另一种方法是通过 CocoaPods,来配置集成,但这种集成方式不在本教程的讲解范围内。

手动将你的框架连接到 iOS 项目:

1.在 Xcode 中,双击项目名称打开 iOS 项目设置。

2.在项目设置的 Build Phases “构建阶段” 选项卡上,点击 “+” 并添加 New Run Script Phase “新的运行脚本阶段“。

3.添加以下脚本:

4.将运行脚本阶段移动到编译源代码阶段之前

5.在“构建设置”选项卡中,在“构建选项”下禁用“用户脚本沙盒”。

这可能需要重新启动你的 Gradle 守护进程,如果你在未先禁用沙盒功能的情况下构建了 iOS 项目。请停止可能已被置于沙盒中的 Gradle 守护进程。

./gradlew --stop

6.在 Xcode 中构建项目。如果一切设置正确,项目将成功构建。

如果你有与默认的 “调试(Debug)” 或 “发布(Release)” 不同的自定义构建配置,在 “构建设置” 选项卡中,在 “用户自定义” 下添加 “KOTLIN_FRAMEWORK_BUILD_TYPE” 设置,并将其设为 “调试(Debug)” 或 “发布(Release)”。

使用 Swift 中的共享模块

1.在 Xcode 中,打开 ContentView.swift 文件并导入共享模块:

import shared

2.为检查连接是否正常,使用跨平台应用共享模块中的 greet() 函数。

import SwiftUI
import sharedstruct ContentView: View {var body: some View {Text(Greeting().greet()).padding()}
}

3.从 Xcode 运行该应用程序以查看结果:

4.在 ContentView.swift 文件中,编写使用共享模块中的数据并渲染应用程序用户界面的代码

import SwiftUI
import sharedstruct ContentView: View {@State private var username: String = ""@State private var password: String = ""@ObservedObject var viewModel: ContentView.ViewModelvar body: some View {VStack(spacing: 15.0) {ValidatedTextField(titleKey: "Username", secured: false, text: $username, errorMessage: viewModel.formState.usernameError, onChange: {viewModel.loginDataChanged(username: username, password: password)})ValidatedTextField(titleKey: "Password", secured: true, text: $password, errorMessage: viewModel.formState.passwordError, onChange: {viewModel.loginDataChanged(username: username, password: password)})Button("Login") {viewModel.login(username: username, password: password)}.disabled(!viewModel.formState.isDataValid || (username.isEmpty && password.isEmpty))}.padding(.all)}
}struct ValidatedTextField: View {let titleKey: Stringlet secured: Bool@Binding var text: Stringlet errorMessage: String?let onChange: () -> ()@ViewBuilder var textField: some View {if secured {SecureField(titleKey, text: $text)}  else {TextField(titleKey, text: $text)}}var body: some View {ZStack {textField.textFieldStyle(RoundedBorderTextFieldStyle()).autocapitalization(.none).onChange(of: text) { _ inonChange()}if let errorMessage = errorMessage {HStack {Spacer()FieldTextErrorHint(error: errorMessage)}.padding(.horizontal, 5)}}}
}struct FieldTextErrorHint: View {let error: String@State private var showingAlert = falsevar body: some View {Button(action: { self.showingAlert = true }) {Image(systemName: "exclamationmark.triangle.fill").foregroundColor(.red)}.alert(isPresented: $showingAlert) {Alert(title: Text("Error"), message: Text(error), dismissButton: .default(Text("Got it!")))}}
}extension ContentView {struct LoginFormState {let usernameError: String?let passwordError: String?var isDataValid: Bool {get { return usernameError == nil && passwordError == nil }}}class ViewModel: ObservableObject {@Published var formState = LoginFormState(usernameError: nil, passwordError: nil)let loginValidator: LoginDataValidatorlet loginRepository: LoginRepositoryinit(loginRepository: LoginRepository, loginValidator: LoginDataValidator) {self.loginRepository = loginRepositoryself.loginValidator = loginValidator}func login(username: String, password: String) {if let result = loginRepository.login(username: username, password: password) as? ResultSuccess  {print("Successful login. Welcome, \(result.data.displayName)")} else {print("Error while logging in")}}func loginDataChanged(username: String, password: String) {formState = LoginFormState(usernameError: (loginValidator.checkUsername(username: username) as? LoginDataValidator.ResultError)?.message,passwordError: (loginValidator.checkPassword(password: password) as? LoginDataValidator.ResultError)?.message)}}
}

5.在 simpleLoginIOSApp.swift 文件中,导入共享模块并为 ContentView () 函数指定参数。

import SwiftUI
import shared@main
struct SimpleLoginIOSApp: App {var body: some Scene {WindowGroup {ContentView(viewModel: .init(loginRepository: LoginRepository(dataSource: LoginDataSource()), loginValidator: LoginDataValidator()))}}
}

6.运行 Xcode 项目,你会看到 iOS 应用显示出登录表单。在用户名处输入 “Jane”,密码处输入 “password”。应用会使用共享代码对输入内容进行验证。

享受成果吧 —— 只需更新一次逻辑。

现在,你的应用程序实现了跨平台。你只需在一处更新业务逻辑,就能在安卓和 iOS 系统上看到相应的变化。

1.在 Android Studio 中,更改用户密码的验证逻辑:“password” 不应该是一个有效的选项。为此,更新 LoginDataValidator 类的 checkPassword () 函数:

package com.jetbrains.simplelogin.shared.dataclass LoginDataValidator {
//...fun checkPassword(password: String): Result {return when {password.length < 5 -> Result.Error("Password must be >5 characters")password.lowercase() == "password" -> Result.Error("Password shouldn't be \"password\"")else -> Result.Success}}
//...
}

2.在 Android Studio 中,为 iOS 应用添加运行配置:

在主菜单中选择 “运行(Run)| 编辑配置(Edit configurations)”。

要添加新配置,点击加号,然后选择 “iOS 应用程序(iOS Application)”。

将该配置命名为 “SimpleLoginIOS”。

在 “Xcode 项目(Xcode project)” 文件字段中,选择 simpleLoginIOS.xcodeproj 文件的位置。

在 “执行目标(Execution target)” 列表中选择一个模拟环境,然后点击 “确定(OK)”

3.从 Android Studio 运行 iOS 和安卓应用,查看相应变化。

你可以查看本教程的最终代码。最终代码icon-default.png?t=O83Ahttps://github.com/Kotlin/kmp-integration-sample/tree/final.

还有什么别的可以分享呢?

你已经共享了应用程序的业务逻辑,但你也可以决定共享应用程序的其他层。例如,ViewModel 类的代码在安卓和 iOS 应用中几乎相同,如果你的移动应用需要有相同的表示层,那么你可以共享这部分代码。

接下来做什么?

一旦你让安卓应用实现跨平台,就可以继续进行以下操作:

添加对多平台库的依赖

添加安卓依赖

添加 iOS 依赖

你还可以查看社区资源:

视频:如何将安卓项目迁移至 Kotlin 多平台

  • Add dependencies on multiplatform libraries

  • Add Android dependencies

  • Add iOS dependencies

视频:让 Kotlin JVM 代码适配 Kotlin 多平台的三种方法

如何在Android应用中添加对多平台库的依赖?

有哪些常见的Kotlin多平台库可以添加到Android应用中?

社区资源中还有哪些关于Kotlin多平台的内容值得参考?

  • Video: How to migrate an Android project to Kotlin Multiplatform

  • Video: 3 ways to get your Kotlin JVM code ready for Kotlin Multiplatform

相关文章:

【Compose multiplatform教程】05 IOS环境编译

了解如何使现有的 Android 应用程序跨平台&#xff0c;以便它在 Android 和 iOS 上都能运行。您将能够在一个位置编写代码并针对 Android 和 iOS 进行测试一次。 本教程使用一个示例 Android 应用程序&#xff0c;其中包含用于输入用户名和密码的单个屏幕。凭证经过验证并保存…...

3D滤波器处理遥感tif图像

import cv2 import numpy as np from osgeo import gdal# 定义 Gabor 滤波器的参数 kSize 31 # 滤波器核的大小 g_sigma 3.0 # 高斯包络的标准差 g_theta np.pi / 4 # Gabor 函数的方向 g_lambda 10.0 # 正弦波的波长 g_gamma 0.5 # 空间纵横比 g_psi np.pi / 2 # …...

fisco bcosV3 Table智能合约开发

环境 &#xff1a; fisco bcos 3.11.0 webase-front : 3.1.1 console 3.8.0 table合约【3.2.0版本后的】 前言 最近在做毕设&#xff0c;数据的存储方式考虑使用fisco-bcos的table表存储&#xff0c;经过这几天的研究&#xff0c;发现对于fisco2和 fisco3版本的table表合约功能…...

leetcode刷题记录(四十八)——128. 最长连续序列

&#xff08;一&#xff09;问题描述 128. 最长连续序列 - 力扣&#xff08;LeetCode&#xff09;128. 最长连续序列 - 给定一个未排序的整数数组 nums &#xff0c;找出数字连续的最长序列&#xff08;不要求序列元素在原数组中连续&#xff09;的长度。请你设计并实现时间复…...

HTML中如何保留字符串的空白符和换行符号的效果

有个字符串 储值门店{{thing3.DATA}}\n储值卡号{{character_string1.DATA}}\n储值金额{{amount4.DATA}}\n当前余额{{amount5.DATA}}\n储值时间{{time2.DATA}} &#xff0c; HTML中想要保留 \n的换行效果的有下面3种方法&#xff1a; 1、style 中 设置 white-space: pre-lin…...

Linux入门——环境基础开发(上)

Linux 软件包管理器 yum 什么是软件包 在Linux操作系统中&#xff0c;安装软件的方式通常较为复杂&#xff0c;其基本流程涉及下载程序源代码并通过编译得到可执行程序。然而&#xff0c;这种方法需要开发者具备一定的编程知识和环境配置能力&#xff0c;对于许多用户而言&am…...

c++类和对象---下

文章目录 一、类的静态成员 1.1.静态成员变量&#xff1a;所有对象共享的成员变量。 1.2.静态成员函数&#xff1a;可以访问静态成员变量&#xff0c;但不能访问非静态成员变量。 二、类的继承 2.1.继承&#xff1a;子类继承父类的成员变量和成员函数。 2.2.多态&#xff1a;基…...

组件中的Props

在项目开发中,在开发某些界面时,我们可以将一些代码封装成组件来简化代码。但是,如果某些情况下组件中的某些属性不是一成不变的(比如一个头像+姓名的组件,每次使用时都需要改变其图像src和姓名字符串),我们就可以使用Props。 我们要使用Props,我们需要先在组件中声明…...

并行服务、远程SSH无法下载conda,报错404

原下载代码无效&#xff0c;报错404 wget -c https://repo.anaconda.com/archive/Anaconda3-2023.03-1-Linux-x86_64.sh 使用下面代码下载 wget --user-agent"User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12…...

迅为RK3568开发板篇OpenHarmony配置HDF驱动控制LED-新增 topeet子系统-编写 bundle.json文件

bundle.json 文件内容如下所示&#xff1a; 下面是对各个字段的解释&#xff1a; 1. name: "ohos/demos" - 这是组件或项目的名称&#xff0c;这里表示它属于 OHOS&#xff08;OpenHarmony OS&#xff09;生态系统下的一个名为"demos"的组件。 2. descri…...

深度剖析RabbitMQ:从基础组件到管理页面详解

文章目录 一、简介二、Overview2.1 Overview->Totals2.2 Overview->Nodesbroker的属性2.3 Overview->Churn statistics2.4 Overview->Ports and contexts2.5 Overview->Export definitions2.6 Overview->Import definitions 三、Connections连接的属性 四、C…...

usb通过hdc连接鸿蒙next的常用指令

参考官方 注册报名https://www.hiascend.com/developer/activities/details/44de441ef599450596131c8cb52f7f8c/signup?channelCodeS1&recommended496144 hdc-调试命令-调测调优-系统 - 华为HarmonyOS开发者https://developer.huawei.com/consumer/cn/doc/harmonyos-guid…...

【落羽的落羽 C语言篇】文件操作

文章目录 一、文件的概念和分类1. 概念和分类2. 文件名3. 数据文件 三、文件操作1. 文件的打开和关闭1.1 流1.2 文件指针1.3 文件的打开和关闭 2. 文件的顺序读写3. 文件的随机读写4. 文件读取的判定5. 文件缓冲区 一、文件的概念和分类 1. 概念和分类 文件是用来保存数据的。…...

RNN之:LSTM 长短期记忆模型-结构-理论详解-及实战(Matlab向)

0.前言 递归&#xff01;循环神经网络Recurrent Neural Network 循环神经网络&#xff08;又称递归神经网络&#xff0c;Recurrent Neural Network&#xff0c;RNN&#xff09;。是一种用于处理序列数据的神经网络结构&#xff0c;具有记忆功能&#xff0c;能够捕捉序列中的时…...

战略与规划方法——深入解析波士顿矩阵(BCG Matrix):分析产品组合的关键工具

深入解析波士顿矩阵(BCG Matrix):分析产品组合的关键工具 在现代商业管理中,合理地分析和管理产品组合对于企业的成功至关重要。波士顿矩阵(BCG Matrix),又称为成长份额矩阵,是一种由波士顿咨询集团(Boston Consulting Group)在20世纪70年代提出的战略工具,用于帮助…...

【记录52】el-table-column 添加fixed属性 滚动条无法滑动

问题&#xff1a; el-table-column 添加fixed属性 滚动条无法滑动 使用element UI组件&#xff0c;用到el-table的el-table-column的fixed属性时&#xff0c;当滚动条长度小于固定列时&#xff0c;滚动条无法通过鼠标去点击滑动操作 原因 fixed是用来固定列的属性&#xff0c;其…...

晨辉面试抽签和评分管理系统之十:如何搭建自己的数据库服务器,使用本软件的网络版

晨辉面试抽签和评分管理系统&#xff08;下载地址:www.chenhuisoft.cn&#xff09;是公务员招录面试、教师资格考试面试、企业招录面试等各类面试通用的考生编排、考生入场抽签、候考室倒计时管理、面试考官抽签、面试评分记录和成绩核算的面试全流程信息化管理软件。提供了考生…...

主链和Layer2之间资产转移

主链和Layer2之间资产转移 主链和Layer2之间资产转移是实现Layer2技术的关键环节,以下是资产转移的流程、流行解决方案及原理: 资产从主链转移到Layer2 用户在主链上发起一笔交易,将资产发送到一个特定的智能合约地址,这个合约是主链与Layer2之间的桥梁。智能合约会锁定用…...

麒麟操作系统服务架构保姆级教程(十)rewrite跳转

如果你想拥有你从未拥有过的东西&#xff0c;那么你必须去做你从未做过的事情 我们访问一个网页的时候会遇到一些奇形怪状的url地址&#xff0c;想优化一下&#xff0c;看着顺眼一点&#xff0c;或者打开一个短视频软件想摸鱼刷一会视频&#xff0c;在打开界面的时候无意间按到…...

MySQL表的创建实验

创建并使用数据库mydb6_product 。 mysql> create database mydb6_product; Query OK, 1 row affected (0.01 sec)mysql> use mydb6_product; Database changed 新建employees表。 对于gender&#xff0c;有默认值意味着不为空&#xff0c;在建表时可以选择不写not nul…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

#Uniapp篇:chrome调试unapp适配

chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器&#xff1a;Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器

一、原理介绍 传统滑模观测器采用如下结构&#xff1a; 传统SMO中LPF会带来相位延迟和幅值衰减&#xff0c;并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF)&#xff0c;可以去除高次谐波&#xff0c;并且不用相位补偿就可以获得一个误差较小的转子位…...

shell脚本质数判断

shell脚本质数判断 shell输入一个正整数,判断是否为质数(素数&#xff09;shell求1-100内的质数shell求给定数组输出其中的质数 shell输入一个正整数,判断是否为质数(素数&#xff09; 思路&#xff1a; 1:1 2:1 2 3:1 2 3 4:1 2 3 4 5:1 2 3 4 5-------> 3:2 4:2 3 5:2 3…...

Qwen系列之Qwen3解读:最强开源模型的细节拆解

文章目录 1.1分钟快览2.模型架构2.1.Dense模型2.2.MoE模型 3.预训练阶段3.1.数据3.2.训练3.3.评估 4.后训练阶段S1: 长链思维冷启动S2: 推理强化学习S3: 思考模式融合S4: 通用强化学习 5.全家桶中的小模型训练评估评估数据集评估细节评估效果弱智评估和民间Arena 分析展望 如果…...