uni-app-配合iOS App项目开发apple watch app

假设你已经用uni-app开发好了一个iOS端的app,现在想要开发一个配套的apple watch app。改怎么去开发呢?是不是一头雾水,这篇文章就会介绍一些apple watch app开发的知识以及如何在uni-app开发的iOS app基础上去开发配套的watch app。

一、apple watch 开发知识

apple watch app类型

首先,我们来了解下apple watch app有哪些类型。

我们在新建一个WatchOS app的项目时可以看到,watch app有2种类型。一个是独立的watch app(Watch-only app),一个是依赖iOS app的watch app(with Companion iOS App),那么他们有什么区别呢?我将从几个不同的角度去介绍:

  • 安装

watch-only的只能通过apple watch上的appStore去下载安装

with iOS App的,可以通过手机上Watch应用去安装可使用的watch app,当然也可以通过appStore下载

  • 开发

watch-only新建项目时只有watchKit app和watchKit extension。

with iOS App的则会有一个iOS app的target

UI框架说明

watchKit app虽然可以通过UIKit,使用swift或者OC来开发,但是官方建议的是使用SwiftUI这个新的UI框架开发。因为 SwiftUI 具有声明式编程、更简洁的语法、更好的跨平台性以及对数据绑定和响应式编程的良好支持等优点,特别适合手表、VR眼镜这种屏幕较小、交互相对简单的设备。

swiftUI的语言和swift还是有较大的区别的,UI控件的使用、生命周期的管理等都大不一样,还是需要各位同学去系统的学习一下。

数据请求类型

有一部分watch app是工具类的App(比如闹钟),不需要获取网络数据。

有一部分watch app是只需要获取健康数据(步数、心率、睡眠等),通过原生的HealthKit即可获取。

有一部分watch app需要联网获取在线数据,就需要通过Alamofire等网络库或者原生的URLSession来实现数据请求。

还有一种特殊的数据获取方式,就是通过Watch Connectivity实现watch app和手机app数据交换,数据可以通过手机app请求拿到(在线或者其他方式),然后传输给watch app。watch app也可以传输数据给手机app。下面会详细讲下这个Watch Connectivity。

Watch Connectivity

这里我们是有2个设备,一个watch,一个iphone。对应项目里是有一个app的target,一个watchKit的target。

WCSessionManager单例封装

首先我们来封装一个Manager来管理数据的发送、接收以及最开始的初始化。

通过shared实现单例访问,持有session属性和一个消息回调callBack。同时需要遵循WCSessionDelegate实现相关代理方法(状态变化、接收消息等)。

session是WCSession类型,整个过程的数据交换都是通过WCSession来实现的。

Swift 复制代码
import WatchConnectivity

final class WCSessionManager: NSObject {
    
    static let shared = WCSessionManager()
    var session = WCSession.default
    var callBack: ((NSDictionary)->Void)!
    
    private override init() {
        super.init()
        if WCSession.isSupported() {
            session.delegate = self
            session.activate()
        }
    }
    
    func initWithCallBack(callback: @escaping (NSDictionary) -> Void) {
        let sessionManager = WCSessionManager.shared
        sessionManager.callBack = callback
    }
    
    func sendMessage(message: [String: Any]) {
        session.sendMessage(message, replyHandler: nil)
    }
}

// MARK: - WCSessionDelegate
extension WCSessionManager: WCSessionDelegate {
    
    #if os(iOS)
    func sessionDidBecomeInactive(_ session: WCSession) {
        print("\(#function): activationState = \(session.activationState.rawValue)")
    }

    func sessionDidDeactivate(_ session: WCSession) {
        // Activate the new session after having switched to a new watch.
        session.activate()
    }

    func sessionWatchStateDidChange(_ session: WCSession) {
        print("\(#function): activationState = \(session.activationState.rawValue)")
    }
    
    func session(_ session: WCSession, didReceiveMessageData messageData: Data, replyHandler: @escaping (Data) -> Void) {
        print("didReceiveMessageData")
    }
    #endif
    
    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
        // 处理激活完成
        print("\(#function): activationState = \(session.activationState.rawValue)")
    }
    
    func session(_ session: WCSession, didReceiveMessage message: [String: Any]) {
        // 处理接收到的消息
        print("收到message: \(message)")
    }
    
    func session(_ session: WCSession, didReceiveMessage message: [String: Any], replyHandler: @escaping ([String: Any]) -> Void) {
        // 处理需要回复的消息
        print("收到message: \(message)")
        replyHandler(["status": "received"])
    }
    
    func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
        print("收到userInfo: ")
        print(userInfo)
    }
    
    func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) {
        print("收到context: ")
        print(applicationContext)
    }
}

初始化并设置回调处理

1、在iOS app对应target的AppDelegate(或者其他页面中也行)调用initWithCallBack实现初始化并设置收到消息后回调处理。initWithCallBack内部会调用.shared从而触发init方法,再通过内部session.delegate = self和session.activate()完成初始化。

2、在watchkit app对应的target的里的AppDelegate文件中调用initWithCallBack实现初始化并设置收到消息后回调处理。这里需要注意watchKit app里本身没有AppDelegate文件,需要自己新建并且在main主入口中关联。

新建:

Swift 复制代码
import WatchKit
import WatchConnectivity

class AppDelegate: NSObject, WKApplicationDelegate {
        
    override init() {
        super.init()
        assert(WCSession.isSupported(), "This sample requires a platform supporting Watch Connectivity!")
        
        WCSessionManager.shared.initWithCallBack { data in
            
        }
    }
}

关联:

Swift 复制代码
import SwiftUI

@main
struct WatchApp_Watch_AppApp: App {
    @WKApplicationDelegateAdaptor var appDelegate: AppDelegate
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

3、链接状态介绍。我们在调用初始化的方法后,会进入到对应的代理方法中,返回WCSession的状态session.activationState。WCSessionActivationState 枚举定义:

  • activated:会话已激活,可正常通信。

  • inactive :设备已配对但会话未激活(需调用 activate() 方法)。

  • notPaired:设备未配对,无法通信。

  • notConnected:设备已配对但未连接(如蓝牙断开)。

数据发送

我们先来了解下Watch Connectivity发送数据有哪几种方式:

  1. 短消息(Messages):实时发送少量数据(如布尔值、字符串、字典)。
  2. 用户信息(User Info):传输字典类型数据,支持后台异步传输。
  3. 文件传输(Transfer File):发送较大文件(如图片、视频)。
  4. 数据更新(Update Context):更新共享的上下文数据(如用户设置、当前状态)。

一般我们只用到前面2种,可以直接调用WCSessionManager中的方法实现发送:

Swift 复制代码
    WCSessionManager.shared.sendMessage(["a":"aa"])
    WCSessionManager.shared.transferUserInfo(["b":"baba"])

二、绑定uni-app开发的iOS App

前面第一部分介绍了apple watch app开发的部分。那么怎么将watch app绑定到用uni-app开发的App中呢?

一开始我先为iPhone和iWatch分别创建了2个独立的项目,按规则设置bundleID、AppGroups等,测试发现没办法进行通讯。运行会提示对方App未安装,查询资料是没有设置target dependencies,但是2个分开的项目没办法设置target dependencies。所以还是得在一个项目里创建2个target来分别开发2个端。

于是就想到将uni-app项目通过本地离线打包,得到一个可以在原生xcode中运行的项目工程。期间研究离线打包的知识也是花了一点时间,而且由于uni-app用到了UTS插件,还需要将这些插件打包成iOS原生的framework加到离线工程里才能使用。就在向官方技术咨询uts插件打包framework的问题时,了解到最新的HBuilderX支持Watch App产物添加。也就是可以把原生打包出来的ipa中的watch app部分,配置到uni-app工程中,再通过云打包,可以得到包含watchKit app的iOS app。这简直太香了,于是我就放弃当前离线工程的方式,开始新的方案。

现在开始介绍新的方案,也是最终方案:

  1. 首先在Xcode中新建一个iOS app工程,就和开发普通App一样即可。
  2. 然后查看项目Target并新建一个Target,选WatchOS --> App,类型选择"Watch App for Existing iOS App"
  3. 然后修改watchApp 这个target里的bundleId,注意这里有严格的格式要求。比如iOS App里bundleID是com.***.app,那么watch里就要用com.***.app.watchkitapp。
  4. 然后再配置App Groups,这一步可以参考苹果文档或者网络上教程。
  5. 完成上面这些操作,就算是创建好了一个基础的框架了。接下来就是开发功能相关的了,此处省略N万字。
  6. 开发完功能后,就是打包了。Scheme选中iOS App这个,和之前开发iOS App普通打包一样,打包得到ipa。然后解压ipa,找到里面watch文件夹,复制watch文件夹里面的.app 文件。
  7. 关联watch app到 uni-app工程。在 uni-app/uni-app x 项目原生资源目录 "nativeResources" 的 "ios" 目录下创建 "Watch"子目录,并添加 Watch App 二级制文件,结构如下图。可以在ios-watch.json中配置云打包时重签名设置。
  8. 云打包制作自定义基座,安装App调试,测试是否同步有可使用的watch App。

至此,在uni-app开发的App基础上开发一个配套的watch app方案就介绍完了。

相关推荐
中了500w1 小时前
uniapp动态插槽打包成小程序不生效?
uni-app
Q_Q19632884753 小时前
python+uniapp基于微信小程序的高校二手商品交易系统
spring boot·python·微信小程序·django·flask·uni-app·node.js
莫空00004 小时前
uView Plus TabBar完美适配iOS安全区:告别底部小横条遮挡烦恼!
微信小程序·uni-app
万岳软件开发小城6 小时前
基于Uniapp+PHP的教育培训系统开发指南:网校源码实战剖析
uni-app·php·软件开发·在线教育系统源码·教育平台搭建·教育app开发·网校小程序
從南走到北20 小时前
设备巡检系统小程序ThinkPHP+UniApp
微信小程序·小程序·uni-app·微信公众平台
刘大浪1 天前
uniapp 实战新闻页面(一)
android·uni-app
我是shenzhongchaoii1 天前
写100个前端效率工具(1):uni-app海报生成 uni-wxml2canvas
uni-app
moxiaoran57531 天前
uni-app项目实战笔记16--实现头部导航栏效果
笔记·uni-app
Q_Q5110082851 天前
python+uniapp基于微信小程序健康管理系统
spring boot·python·微信小程序·django·flask·uni-app·node.js