跳转到内容

NativeScript — 用 JS/TS 直接驱动原生控件

待复核

NativeScript 让你用 JavaScript / TypeScript 写 iOS 与 Android(以及 visionOS)应用,运行时把前端代码映射到系统原生控件,而不是塞进 WebView。日常类比:不是在网页外壳里套页面,而是给每个平台各配一套”遥控器”——按钮同一套按法,动作落到 UIKit / Android View 等原生组件上。

最小心智模型:你写 XML(或框架组件)描述界面,写 TS 写逻辑;NativeScript runtime 在设备上把 ButtonLabel 变成真正的原生 View,并可直接调用相机、定位等原生 API。

官方 monorepo(约 2.5 万 star)提供 @nativescript/core 与各平台 types;可用 Angular / Vue / React / Solid / Svelte 等前端范式驱动同一套原生层。

和”用网页假装 App”不同:用户滑动的是系统列表,点的是系统按钮,无障碍与平台手势也更接近原生应用。

不理解 NativeScript,下面这些事会很难解释:

  • 为什么有人坚持”跨端”却拒绝 Cordova / Ionic 式 WebView——他们要的是原生控件手感,不是套壳网页
  • 为什么同一套 JS 业务仍要维护两套运行时——iOS 与 Android 的桥接与生命周期并不对称
  • 为什么插件生态比 UI 组件库更决定项目生死——相机、推送、BLE 几乎都走 native plugin
  • 为什么它和 react-native / flutter 常被放在同一张选型表,却不是同一条技术路线
  1. XML + JS/TS 构建模型:视图常用 XML 描述组件树,逻辑在 TS。类比:剧本写站位(XML),演员念台词(TS);舞台上的人仍是原生演员,不是网页投影。

  2. 双端(多端)运行时:NativeScript 为 iOS / Android 等维护独立 runtime,把 JS 调用转到原生。同名 API 行为可能不同,需要自己的抽象层。类比:同一遥控器说明书,两台电视频道编号不一样。

  3. 直接触达原生 API + 插件:不必为每个系统能力重写 Java/Swift 业务,但第三方 plugin 质量参差,权限与原生依赖要分层接入。类比:万能转接头很多,劣质接头会烧掉设备。

Terminal window
npm install -g nativescript
ns create my-app
cd my-app
ns run android # 或 ns run ios

逐部分解释

  • ns create 生成带 @nativescript/core 的工程骨架
  • ns run 编译 JS/TS,打包进对应平台运行时,装到模拟器或真机
  • 这一步验证的是”工具链通了”,还不是业务抽象是否干净
<Page xmlns="http://schemas.nativescript.org/tns.xsd">
<StackLayout>
<Label text="{{ message }}" />
<Button text="点我" tap="onTap" />
</StackLayout>
</Page>
export function onTap() {
this.set("message", "已点击");
}

逐部分解释

  • Label / Button / StackLayout 会映射成原生布局与控件,不是 DOM
  • tap="onTap" 把原生点击接到 TS 方法
  • {{ message }} 是绑定:改数据后视图更新走框架运行时,不是手动改 DOM

案例 3:平台差异用 adapter 包一层

Section titled “案例 3:平台差异用 adapter 包一层”
import { isIOS } from "@nativescript/core";
export function pickPhoto() {
if (isIOS) return openIosPhotoLibrary();
return openAndroidCameraOrGallery();
}

逐部分解释

  • 业务页只调 pickPhoto(),不散落 if (isIOS)
  • 权限声明、相册 vs 相机入口放在 adapter,避免 UI 层被平台细节污染
  • BLE / 推送等同理:统一调用层 + 原生通信层分离
  1. 同名 API 两端行为不同:返回值、生命周期、权限弹窗时机常不一致,原因是两套 runtime 而非”写错一行 JS”。
  2. 插件版本与 runtime 绑死:升级 @nativescript/core 后旧 native plugin 编译失败很常见,要锁版本并做两端回归。
  3. 桥接层报错不透明:堆栈常停在原生 side,JS 里只看到模糊异常,需要同时看 Xcode / Logcat。
  4. 把 Web 布局习惯原样搬过来:CSS 子集与原生布局规则不同,长列表不做虚拟化时滚动会卡。

适用

  • 前端团队想复用 TS 逻辑与 UI 描述,又要原生控件手感
  • 中小型业务 App(表单、列表、中等原生能力),双端维护成本敏感
  • 已接受”要管插件与原生依赖”的团队

不适用

  • 极致原生动画 / 游戏级帧率——更常选纯原生或 flutter 自绘
  • 团队无人愿意碰 Xcode / Android 构建链
  • 强依赖刚发布的平台-only API,且社区 plugin 尚未跟上
  • 2014–2015 年:Telerik 推出 NativeScript,主打”JS 直接调原生 API”,区别于当时流行的 Cordova 套壳
  • 2015 年:GitHub 仓库公开,跨端热潮中与 Cordova / React Native 并列被讨论
  • 收购之后:Progress 收购 Telerik,产品继续开源维护;官方加强 Angular / Vue 等集成
  • 社区分化:RN 与 Flutter 拿走大部分心智份额后,NativeScript 更强调”多前端框架 × 原生 API 直达”
  • 近年:runtime 扩展到 visionOS 等;定位变成差异化路线,而不是”唯一跨端答案”
  1. 跨端不是一次转译,是持续维护两套运行时与插件
  2. 桥接层是架构核心——性能与排错往往卡在这里,不在业务 if/else
  3. 平台差异要用 adapter 收口,不要泄漏进每个页面
  4. 选型先问”要不要真原生控件”:要 Web 套壳看 ionic-framework / capacitor;要 JS 原生桥看 NS / RN;要自绘 UI 看 Flutter
  5. 插件治理成本是隐性主成本——UI 写得再快,原生依赖一乱,发布节奏就会塌
  • react-native —— JS 跨端原生桥的主流对照
  • flutter —— 自绘 UI 路线,性能模型不同
  • ionic-framework —— Web 技术栈 + 原生壳
  • capacitor —— 现代 WebView 桥,常与 Ionic 搭配
  • expo —— RN 工具链与托管服务对照
  • cordova —— 早期 WebView 插件生态前史
  • webview —— 套壳路线的底层对照,帮助理解 NS 为何坚持原生控件
  • ionic-framework —— Ionic Framework — 用网页技术做跨端 App 的 UI 工具箱