跨平台开发

作者: shaokang 时间: September 23, 2024字数:7615

简介

随着移动应用的发展,出现了很多的跨平台开发方案,接下来我们来介绍不同的跨平台方案。

原生编程和跨平台编程是两种主要的应用开发方式。原生应用主要利用开发平台和操作系统官方提供的编程语言和工具进行开发。比如,iOS 原生应用主要采用 Objective-C 和 Swift,而 Android 原生应用则主要使用 Java 或 Kotlin。

相对而言,跨平台应用则采用非官方提供的编程语言和工具,这些语言和工具能够在多个平台上运行,例如 Ionic、Xamarin、React Native、Apache Cordova 和 Flutter 等框架。这些工具的出现,使得开发者能够更高效地开发出能在多个操作系统上运行的应用。

进一步来看,原生执行应用和混合执行应用也存在显著差异。原生执行应用,无论其源代码是采用原生语言还是跨平台语言编写,最终都会被编译为机器可直接执行的代码,如 AOT 或 JIT,同时它们还会利用原生的 UI 组件。Xamarin、React Native 和 Flutter 等框架开发的应用便属于此类。

另一方面,混合执行应用主要采用基于 Web 的跨平台编程语言(如 HTML、CSS、JavaScript/ECMAScript 或其超集如 SCSS 和 TypeScript)进行编写,并在一个原生的外壳,如 WebView 中执行。这种开发方式使得应用能够在保持跨平台特性的同时,也能在一定程度上利用原生设备的功能。

优缺点对比

Native

  • 优点:

    • 卓越的性能和稳定性
    • 出色的用户体验
    • 强大的开发支持和工具
  • 缺点:

    • 高昂的开发成本
    • 漫长的开发周期
    • 复杂的维护和升级过程

WebApp

  • 优点:

    • 上手容易,开发迅捷
    • 低成本,跨平台兼容性
    • 简化的维护和升级流程
    • 能够实时获取最新代码
  • 缺点:

    • 受浏览器功能限制
    • 交互体验可能欠佳
    • 相比原生应用性能较差

Hybrid

  • 优点:

    • 跨平台兼容性
    • 一致的外观和功能
    • 较低的开发成本
    • 简化的维护和升级流程
    • 能够调用设备特性
  • 缺点:

    • 性能不及原生应用
    • 无法完全利用设备特性

跨平台方案

Web 渲染

基于 Web 渲染的混合开发 App 结合了 Web 技术(HTML、CSS、JavaScript)与原生容器的优势。它运用原生容器中的 WebView 组件渲染 UI,并通过 JavaScript 调用原生 API,实现跨平台的高效开发与丰富功能。相较于纯 Web 应用,此方式在性能和用户体验上有所提升,同时保留了 Web 开发的效率与跨平台性。流行框架如 Cordova、PhoneGap 和 Ionic 等,为开发者提供了丰富的 API 与插件,支持多平台快速开发。

渲染原理

基于 Web 渲染的混合 App 都内置 WebView 组件,通过 JavaScript 实现本地与 Web 应用的交互。打开应用时,WebView 加载主页面,并允许 JavaScript 访问其 DOM 和 CSS。

常见方案

JSBridge

JSBridge 是 WebView 的前端解决方案,实现 JavaScript 与 Native 的双向通信。它在 Native 端提供 JavaScript 接口,并在 WebView 中注入 JSBridge 对象,从而建立通信桥梁。简言之,通过 JSBridge,WebView 和原生方法可以相互调用。

一、JS 调用 Native 方式

1. 拦截 URL Scheme

概念:URL SCHEME 是一种专为应用间调用设计的链接,形式与普通 URL 相似,但 protocol 和 host 为自定义。

拦截流程:

  • Web 端发送特定 URL Scheme 请求。
  • Native 端拦截并根据请求执行操作。

实现细节:

Android:通过扩展WebViewClient并重写shouldOverrideUrlLoading方法。

public class CustomWebViewClient extends WebViewClient {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        // 场景一:拦截请求、接收scheme
        if (url.startsWith("xxx:")) {
            // 处理逻辑
            // ...
            // 回调更新WebView
            view.loadUrl("javascript:handleResponse(" + responseData + ")");
            return true; // 表示请求已被处理,不再传递
        }
        return super.shouldOverrideUrlLoading(view, url);
    }
}

iOS:使用 WKWebViewdecidePolicyForNavigationAction 方法进行拦截。

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
    if ([navigationAction.request.URL.absoluteString hasPrefix:@"xxx"]) {
        [[UIApplication sharedApplication] openURL:navigationAction.request.URL];
    }
    decisionHandler(WKNavigationActionPolicyAllow);
}

优点

  • 无漏洞,灵活度高,实现 H5 与 Native 无缝切换。
  • 适用于快速开发与迭代,先跳转至 H5 页面,Native 页面开发完成后再拦截跳转,无需修改 H5 链接。

缺点

  • 使用 iframe.src 时需控制 URL 长度,操作复杂且速度较慢。
  • ios 上某些方案采用 ajax 发送同域请求以规避 URL 长度问题,但 WKWebView 不支持。
  • 相较于 API 调用,创建请求耗时更长。

为什么选择 iframe.src 不选择 location.href ? 因为如果通过 location.href 连续调用 Native,很容易丢失一些调用)

2. 注入 API

概念:基于 WebView 功能,向 Window 注入对象或方法,使 JS 能直接调用。

实现细节:

Android:使用 addJavascriptInterface 方法注入(支持 Android 4.2+)。

gpcWebView.addJavascriptInterface(new JavaScriptInterface(this), 'nativeApiBridge');

public class JavaScriptInterface {
    Context mContext;

    JavaScriptInterface(Context c) {
        mContext = c;
    }

    @JavascriptInterface
    public void share(String webMessage) {
        // Native逻辑
    }
}

JS 调用:window.nativeApiBridge.share(xxx);

iOS:UIWebView提供JavascriptCore(支持 iOS 7.0+),而WKWebView提供window.webkit.messageHandlers(支持 iOS 8.0+)。

WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
// 配置设置...
[self.webView.configuration.userContentController addScriptMessageHandler:self name:@"share"];

JS 调用:window.webkit.messageHandlers.share.postMessage(xxx);

总结:

  • URL Scheme 拦截适用于需要灵活切换和快速迭代的场景,但需注意 URL 长度和请求耗时。
  • 注入 API 提供了更直接的 JS 与 Native 交互方式,需注意安全性和平台兼容性。

二、Native 调用 JS 的方式

Native 调用 JS 需要确保 JavaScript 的方法挂载在全局的 window 对象上。

Android 使用 evaluateJavascript,高效且方便获取返回值,不刷新 WebView。

webView.loadUrl("javascript:" + javaScriptString); // 旧方法
webView.evaluateJavascript(javaScriptString, value -> { /* 处理返回值 */ }); // 新方法

iOS 在 WKWebView 中,通过 evaluateJavaScript:javaScriptString 实现,支持 iOS 8.0 及以上。

[webView evaluateJavaScript:@"yourJavaScriptFunction()" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
    // 处理结果或错误
}];
Cordova

Cordova 是由 Nitobi Software(现为 Adobe Systems)开发,后被 Apache 软件基金会收购的混合开发 App 框架。它主要提供以下能力:

  • 通过 API 访问原生设备功能,如摄像头、麦克风等。
  • 统一的 JavaScript 类库及相关的原生后台代码。
  • 跨平台打包,支持 iOS、Android 等多个系统。
  • 自定义插件,允许 JavaScript 调用设备本地功能。

优点:

  • 跨平台支持,一份代码多处运行。
  • Web 技术快速开发,易维护。
  • 插件丰富,简化设备功能访问。
  • 成熟稳定,庞大社区支持。

缺点:

  • 性能受限于 WebView,可能较原生应用慢。
  • 依赖第三方库,存在安全风险。
  • 某些高级功能需原生开发。
  • 开发者需掌握 Web 技术和 Cordova API。
PhoneGap

PhoneGap 与 Cordova 原为同一项目,后因商业原因分立。PhoneGap 为 Adobe 商标,而 Cordova 成为 Apache 项目。两者技术实现基本相同,主要区别在商标所有权和构建工具的使用上。

Ionic

Ionic 专注于感官和应用 UI 交互,在前端简化了 APP 开发。Ionic 提供了优化方案,如内置丰富的原生能力、统一的前端 UI 标准,以及使用多 Webview 机制提升流畅性。

Electron (桌面端开发)

Electron 利用 JavaScript、HTML 和 CSS 构建跨平台桌面应用,兼容 Mac、Windows 和 Linux。成功案例包括 VSCode、Atom、Slack 和新版 QQ。Electron 结合了 Chromium、Node.js 和 Native APIs 的优势。

总结

Web 渲染方案基于原生应用内嵌 Webview,Cordova、PhoneGap、Ionic 等框架封装了全面的原生接口供调用。JSBridge 则专注于 Web 与 native 间的通讯,更灵活。虽然 Web 渲染带来快速开发优势,但 Web 容器的笨重牺牲了性能和用户体验,尤其在复杂交互和动画上表现欠佳。

原生渲染

这种方案又被称为泛 Web 容器方案,这种方案使用 Web 技术来实现应用程序的基本框架和功能,同时放弃了 WebView 渲染,改为使用原生自带的 UI 组件渲染引擎,这种方式可以提供给用户更好的体验和更高的性能。代表框架有 React Native,Weex 等。

这种方案保持了 JavaScript 作为开发语言,支持前端丰富的生态。但由于前端和 Native 的交互需要通过 bridge 交互,因此在处理大量数据和复杂的动画时,bridge 可能会成为性能瓶颈。

渲染原理

原生渲染方案基本上完全放弃了浏览器控件渲染,而是由原生 UI 代替了核心的渲染,仅保持必要的基本控件渲染能力,从而使得渲染过程更为简化。同时也保证了更好的体验和性能。

常见方案

React Native

React Native,由 Facebook 开源,允许开发者用 JavaScript 和 React 构建 iOS 和 Android 原生应用。它将 JSX 转化为原生控件进行渲染,实现了跨平台共享代码。优点包括跨平台支持、快速开发、热重载和强大的社区支持。然而,它可能面临性能挑战,尤其处理大数据和复杂动画时,且有一定学习曲线和平台 API 支持差异。

Weex

Weex 是阿里巴巴开发的跨平台移动框架,采用 Vue.js 的组件化模式,将 JavaScript 代码转化为原生组件。它支持 iOS 和 Android,提供丰富的组件和 API。优点在于跨平台、Vue.js 的高效开发和原生渲染性能。但社区较小,学习成本较高,且插件生态不如 React Native 丰富。

快应用

快应用旨在通过原生应用技术,以 Web 形式提供快速、轻量、即时的体验。它基于 HTML5、CSS3、JavaScript 等 Web 标准,并针对移动设备进行了优化,从而实现了应用的快速访问和使用,无需繁琐的安装和下载过程。缺点是快应用只支持 Android,并不支持 iOS 系统。

自渲染

原生渲染虽提升了性能,但因平台控件标准不统一,导致各端展现差异。为解决此问题,业界推出自绘引擎渲染,该方案源于游戏开发,如在 Cocos Creator、Unity 等框架中,通过原生画布与自定义绘图引擎实现 UI 布局与渲染。

常见方案

Flutter

Flutter 是 Google 开源的构建用户界面(UI)工具包,采用 Skia 渲染引擎进行跨平台渲染,通过嵌入并控制 Skia,确保各平台性能与视觉效果一致。同时,Flutter 使用支持 JIT 和 AOT 的 Dart 语言编写应用与渲染引擎,提升开发效率与代码复用性。

优点

  • 高性能:Flutter 利用 Skia 渲染引擎,实现媲美原生应用的性能。
  • 跨平台:支持 iOS 和 Android,实现代码共享。
  • 热重载:开发过程中可热重载,显著提升开发效率。
  • 组件丰富:提供大量内置及自定义组件选项。
  • Material Design 风格:内置组件库助力打造美观应用。

缺点

  • 语言学习曲线:Dart 语言需一定时间学习与掌握。
  • 第三方库成熟度:作为新框架,部分第三方库稳定性和兼容性待提升。
  • 文件大小:应用相对较大,占用更多存储空间。
  • 平台特定功能支持:某些特定功能可能无法跨平台完全支持。
  • 兼容性:自定义绘图引擎可能引发跨平台兼容问题。

总结

自绘制引擎渲染彻底重塑了跨平台 UI 框架的每一个环节,从渲染逻辑到开发语言都进行了全新的设计。正因如此,它能够最大限度地确保应用在各种平台和设备上的用户体验高度一致。

小程序

小程序的技术革新在于其将渲染层与逻辑层分离,采用多 WebView 与双线程模型架构。渲染层使用 WebView(iOS 的 UIWebView/WKWebView,Android 的 WebView)进行页面渲染,多页面由多个 WebView 分别管理,从而提供更接近原生的用户体验。逻辑层则独立于 WebView,通过 JavaScript 引擎(iOS 的 JavaScriptCore,Android 的 V8)在单独的 Worker 线程中执行 JavaScript 代码。两层之间的通信和网络 IO 都经由 Native 层转发。此外,小程序还融合了原生渲染方案,通过原生组件进一步提升性能。这种架构既限制了直接操作页面的能力,确保开发遵循微信小程序规范,也实现了 Web 渲染与原生渲染的优势互补。

所以这么看,小程序也可以算得上是 Web 渲染和原生渲染的融合解决方案。

常见方案

UniApp

UniApp 是基于 Vue.js 的跨平台开发框架,支持一次编写、多端发布。它通过将 Vue 代码编译为各平台支持的代码,实现微信小程序、H5、iOS、Android 等多平台的快速开发。UniApp 利用 HBuilderX 进行代码转化,确保各平台的高效渲染。

Taro

Taro 是开源的跨平台应用开发框架,采用 React 语法,一次编写即可在微信小程序、H5、React Native 等平台运行。它通过编译器将 React 代码转换为各平台代码,并结合运行时环境,确保应用在各平台的顺畅执行。

MPX

MPX 是基于 Vue.js 的小程序增强框架,可将 Vue 语法编译为原生小程序代码。它优化了小程序开发体验,提供差异化处理工具,让开发者能够更便捷地在小程序中使用 Vue.js 特性。MPX 通过编译和运行时的配合,实现 Vue 组件到小程序自定义组件的转换。

总结

小程序方案凭借其独特的技术架构和融合渲染策略,为开发者提供了一种兼具灵活性、高效性和优质用户体验的应用开发选择。这种方案不仅简化了跨平台应用的开发流程,还确保了应用在各平台上的一致性和兼容性。