- Vercel, một công ty tập trung vào web, đã thử nghiệm nhiều stack công nghệ và mẫu UI với mục tiêu đạt được trải nghiệm native tầm cỡ Apple Design Award, và cuối cùng hoàn thiện ứng dụng với tổ hợp React Native + Expo
- Điểm cốt lõi là trải nghiệm xây dựng dựa trên chat AI: chỉ cần ghi ý tưởng như đang ghi chú, hệ thống sẽ tạo ra ở chế độ nền; từ animation tin nhắn, cuộn, bàn phím cho đến composer kiểu Liquid Glass đều được thiết kế tỉ mỉ để hiện thực hóa tương tác chat ở mức native trên iOS
- Ở phần triển khai chat, họ dùng tổ hợp context và hook dựa trên LegendList, Reanimated, react-native-keyboard-controller, cùng với tính toán
blankSize, contentInset, liên kết chiều cao composer để xử lý mượt mà chiều cao động và thay đổi của bàn phím
- Về cấu trúc mã, họ chia sẻ type, business logic và lớp API giữa web và native; đồng thời nổi bật ở luồng schema OpenAPI dựa trên Zod → Hey API → Tanstack Query, để web v0 và khách hàng của v0 Platform API cùng dùng một endpoint
Tổng quan và mục tiêu của ứng dụng v0 iOS
- Vercel đã phát hành v0 for iOS, ứng dụng di động đầu tiên của mình, và dù là công ty tập trung vào web, họ vẫn đặt mục tiêu tạo ra trải nghiệm native chất lượng cao hướng tới chuẩn Apple Design Award
- Trước khi ra mắt ứng dụng iOS, công ty chủ yếu tập trung vào web, nên việc phát triển một ứng dụng native hoàn chỉnh là lĩnh vực mới
- Vì vậy, trước giai đoạn beta công khai, họ đã thử nghiệm hàng chục phiên bản với nhiều stack công nghệ và mẫu UI khác nhau
- Về tham chiếu, họ lấy cảm hứng từ những ứng dụng biết dùng tốt “ngôn ngữ của iPhone” như Apple Notes và iMessage, với yêu cầu đạt độ hoàn thiện đủ để đứng cạnh các ứng dụng khác trên màn hình chính
- Họ cho biết mình không cố định vào một framework cụ thể, mà triển khai và so sánh thực tế nhiều stack trước khi đi đến kết luận
- Sau nhiều lần thử nghiệm, họ cuối cùng chọn React Native + Expo; sau khi ra mắt, đã nhận được nhiều phản hồi từ nhà phát triển rằng ứng dụng mang cảm giác như một app native, và đó là lý do họ công bố chi tiết kiến trúc kỹ thuật
Định hướng trải nghiệm chat của v0
- v0 iOS hướng đến việc trở thành “công cụ biến ý tưởng nảy ra khi bạn rời xa máy tính thành thứ có thể sử dụng ngay”, định vị mình như thế hệ tiếp theo của ứng dụng ghi chú
- Thay vì mang toàn bộ tính năng hoặc một mobile IDE giống web sang điện thoại, họ ưu tiên một trải nghiệm đơn giản và thú vị để tạo ra thứ gì đó bằng AI khi đang di chuyển
- Trung tâm của trải nghiệm này là giao diện chat, và họ đặt ra các yêu cầu sau
- Tin nhắn mới phải xuất hiện bằng animation mượt mà
- Tin nhắn mới của người dùng phải được cuộn lên đến đầu màn hình để hiển thị
- Tin nhắn của trợ lý khi được stream phải hiển thị với fade in so le theo bậc thang (streaming + độ trễ)
- Ô nhập liệu (composer) phải nổi theo phong cách Liquid Glass, nằm phía trên nội dung có thể cuộn
- Khi mở một cuộc chat cũ, trạng thái ban đầu phải là đã cuộn tới tin nhắn cuối cùng
- Hành vi bàn phím phải tự nhiên và gần với native
- Nhập văn bản phải hỗ trợ dán ảnh và tệp cùng focus/blur bằng cử chỉ pan
- Render Markdown phải nhanh nhưng vẫn hỗ trợ component động
- Dù đã có nhiều mẫu UI chat AI trên mobile, nhưng mẫu dành cho tạo mã AI trên di động gần như chưa tồn tại, nên họ phải tự thiết kế pattern mới, và để đạt được chuẩn đặt ra đã cần rất nhiều công sức, kiểm thử và tinh chỉnh
Thiết kế cấu trúc chat có thể kết hợp
- Để đáp ứng các yêu cầu của chat, phần mã chat được thiết kế theo hướng composable, có thể kết hợp theo từng chức năng
- Vì vậy, họ tạo nhiều Context Provider bao quanh toàn bộ chat, rồi đặt danh sách tin nhắn bên trong cấu trúc đó
- Việc triển khai chat sử dụng các thư viện mã nguồn mở sau
- LegendList: render danh sách hiệu năng cao
- React Native Reanimated: animation và shared value
- react-native-keyboard-controller: điều khiển trạng thái bàn phím và xử lý sự kiện
- Mỗi tin nhắn được render sẽ phân nhánh theo
item.role thành user / assistant / optimistic-placeholder, từ đó dùng component khác nhau cho từng vai trò
Triển khai animation tin nhắn
- Tin nhắn đầu tiên của người dùng được fade in mượt mà bằng shared value của Reanimated
- Hook
useFirstMessageAnimation tính toán chiều cao tin nhắn, chiều cao màn hình và chiều cao bàn phím để điều khiển translateY và opacity
- Tin nhắn đầu tiên của trợ lý sẽ fade in có độ trễ sau khi animation của tin nhắn người dùng hoàn tất
- Với cuộc chat hiện có, họ dùng
scrollToEnd() và điều chỉnh contentInset để đặt tin nhắn mới lên phần trên màn hình một cách tự nhiên
Điều khiển cuộn và bàn phím
- Chất lượng trải nghiệm chat phụ thuộc rất lớn vào độ tự nhiên của hành vi bàn phím, và trong React Native, việc tạo ra cảm giác bàn phím gần với native là một công việc khá khó
- Do khác biệt giữa các phiên bản iOS, đã xuất hiện vấn đề hành vi bàn phím không ổn định;
họ đã hợp tác với maintainer của react-native-keyboard-controller để sửa lỗi và cải thiện hiệu năng
- Hook
useKeyboardAwareMessageList được dùng để kiểm soát chi tiết các sự kiện mở, đóng và kéo bàn phím
- Khi mở cuộc chat cũ, để tự động điều chỉnh vị trí cuộn, họ gọi
scrollToEnd nhiều lần nhằm giải quyết vấn đề chiều cao động
Floating Composer kiểu Liquid Glass và cải thiện ô nhập liệu
- Họ áp dụng hiệu ứng Liquid Glass của iMessage để tạo ô nhập liệu bán trong suốt, dạng nổi
- Dùng
KeyboardStickyView và shared value composerHeight để điều chỉnh contentInset của scroll view theo thời gian thực
- Để giữ cuộn tự động khi chiều cao ô nhập liệu thay đổi, họ dùng hook
useScrollWhenComposerSizeUpdates
- Để giải quyết vấn đề bounce khi cuộn và việc thanh chỉ báo hiện ra ở
TextInput mặc định, họ áp dụng bản vá native cho RCTUITextView
- Đồng thời cải thiện để có thể focus bàn phím bằng cử chỉ vuốt
Dán ảnh và fade in cho nội dung streaming
- Thông qua module Expo, họ phát hiện sự kiện
UIPasteboard để hỗ trợ dán văn bản, hình ảnh và tệp
- Dùng component FadeInStaggeredIfStreaming để hiện thực fade in theo từng từ cho văn bản phản hồi của AI
- Quản lý animation pool để giới hạn số animation đồng thời và tối ưu hiệu năng
- Nội dung đã xem sẽ dùng
DisableFadeProvider để tránh animation lại
Chia sẻ mã giữa web và native, cùng Platform API
- Họ chia sẻ type và hàm helper giữa web và mobile, còn UI và quản lý state thì tách riêng
- Xây dựng framework API an toàn kiểu dữ liệu dựa trên Zod, tự động sinh OpenAPI spec
- Ứng dụng mobile gọi API bằng Hey API + Tanstack Query
- Dựa trên cấu trúc này, họ đã công bố v0 Platform API, cung cấp cùng endpoint cho các nhà phát triển bên ngoài
Styling và component native
- Dùng react-native-unistyles để quản lý theme, hỗ trợ styling nhanh mà không cần truy cập Context
- Thông qua Zeego, họ triển khai menu dựa trên
UIMenu native của iOS
- Họ đã sửa lỗi vị trí Alert xảy ra trên iOS 26 và đóng góp bản vá upstream cho React Native
- Cũng sửa các vấn đề kéo và nhấp nháy liên quan đến modal (formSheet), phối hợp cùng Callstack, Meta và Expo để đưa vào React Native 0.82
Kế hoạch tiếp theo và hợp tác cộng đồng
- Sau khi hoàn thành ứng dụng đầu tiên bằng React Native + Expo, họ dự định giữ nguyên stack này cho các dự án sau và hiện đang hài lòng với lựa chọn đó
- Vercel đang tập trung vào việc xây dựng những sản phẩm tham vọng ở chất lượng cao, và
- cho biết sẽ mở nguồn các bí quyết nội bộ để giúp nhà phát triển web và native có thể tạo ra sản phẩm ở cùng đẳng cấp
- đặc biệt, họ đang tuyển cộng đồng tham gia beta test thư viện mã nguồn mở cho ứng dụng chat AI, đồng thời sẽ tiếp tục đóng góp vào việc cải thiện React Native
Chưa có bình luận nào.