Hướng dẫn

Thêm game vào ứng dụng: chạy game HTML5 trong WebView

Cách đưa một game HTML5 hoàn chỉnh vào ứng dụng Android hoặc iOS bạn đang có: tệp cục bộ hay trên máy chủ, lưu tiến trình, nút quay lại và giấy phép.

Ảnh minh họa game giải đố khai thác mỏ Deepforge, một game HTML5 có thể chạy trong WebView của ứng dụng

Để thêm game vào ứng dụng, bạn không cần nhúng cả một game engine. Bạn cần một WebView: thành phần mà Android và iOS cung cấp để hiển thị nội dung web bên trong một màn hình native. Bạn đặt thư mục game HTML5 hoàn chỉnh vào trong gói ứng dụng hoặc lên máy chủ HTTPS của mình, trỏ WebView tới tệp index.html, và ứng dụng có ngay một mục game chạy trên cùng mã nguồn với bản trình duyệt.

Hướng dẫn này dành cho các đội đã có ứng dụng (app bán lẻ, ngân hàng, nền tảng trường học, câu lạc bộ hay thương hiệu truyền thông) và muốn có game trong app như một tính năng, chứ không phải phát hành app mới lên store. Bài viết đề cập việc chọn tệp cục bộ hay trên máy chủ, các thiết lập WebView làm hỏng game nếu đặt sai, lưu tiến trình, nút quay lại, mẫu nào của chúng tôi phù hợp và giấy phép tính số app ra sao. Chi tiết nền tảng lấy từ tài liệu Android Developers và Apple Developer, đọc ngày 30/10/2026.

Thêm game vào ứng dụng: cách WebView hoạt động

WebView là một engine trình duyệt không có phần vỏ trình duyệt bên ngoài. Mã native của bạn tạo ra nó, quyết định kích thước, thiết lập và nội dung cần tải. Trên Android lớp này tên là WebView; trên iOS là WKWebView. Game HTML5 không phân biệt được: nó thấy một trang, một canvas và bộ nhớ lưu trữ, giống hệt khi chạy trong Chrome hay Safari.

Vì vậy cách này được dùng nhiều cho game trong app. Đội làm game làm việc với HTML, CSS và JavaScript, đội app thêm một màn hình và vài thiết lập, còn cùng thư mục game đó vẫn có thể chạy trên website. Có ba phần cần lên kế hoạch:

  1. Tệp nằm ở đâu: đóng gói trong app, hay tải từ máy chủ HTTPS của bạn.
  2. WebView được cấu hình thế nào: JavaScript, bộ nhớ lưu trữ, địa chỉ mà game chạy.
  3. Game và app giao tiếp ra sao: mở, tạm dừng, nút quay lại, đóng.

Các mẫu của chúng tôi hợp với mô hình này vì mỗi mẫu đi kèm một thư mục game/ có sẵn index.html, làm cho hosting tĩnh, bản thân game không cần PHP hay cơ sở dữ liệu. Thứ không mẫu nào có là phần native. Mọi phiên bản đều ghi app native hoặc bản build cho store trong danh sách “Not included in this edition” (không có trong phiên bản này), nên màn hình WebView là việc của đội bạn, hoặc là một công việc chúng tôi báo giá riêng.

Xem các mẫu game HTML5

Cục bộ hay trên máy chủ: đặt tệp game ở đâu

Cục bộ: game nằm sẵn trong app

Hướng dẫn tải nội dung trong app của Android cho biết nội dung web được biên dịch vào app không cần internet và không tốn dữ liệu di động của người dùng. Bạn chép thư mục game/ vào assets của app và tải từ đó. Cái giá là dung lượng: game làm tăng kích thước tải về, và mỗi lần cập nhật game là một bản phát hành app mới phải qua kiểm duyệt của store.

Trên máy chủ: app tải game từ server của bạn

WebView mở một địa chỉ HTTPS trên tên miền của bạn. Bạn cập nhật game mà không cần build app mới, và app vẫn nhẹ. Cái giá là game cần kết nối mạng, mạng chậm thì lần tải đầu cũng chậm.

Apple có quy định riêng cho trường hợp này. Mục 4.7 trong App Review Guidelines áp dụng cho mini game HTML5 và JavaScript không được nhúng trong tệp binary. Trong các điều kiện của mục này, app không được mở rộng hay mở các API native của nền tảng cho phần mềm đó khi chưa có sự cho phép của Apple, và phải cung cấp một danh mục các phần mềm mà app cung cấp, kèm universal link. Hãy đọc toàn bộ mục 4.7 trước khi chọn cách lưu trên máy chủ cho iOS.

  • Dung lượng app: cục bộ cộng thêm dung lượng của game; trên máy chủ gần như không tăng.
  • Cập nhật: cục bộ cần phát hành app mới; trên máy chủ thay đổi ngay khi bạn tải tệp lên.
  • Kết nối: game cục bộ có thể mở không cần mạng sau khi cài; game trên máy chủ thì cần mạng.
  • Kiểm duyệt: game cục bộ được duyệt cùng với app; trên iOS, game tải từ máy chủ thuộc phạm vi mục 4.7.

Thiết lập WebView trên Android quyết định game chạy hay hỏng

Phần lớn báo lỗi kiểu “game chỉ hiện màn hình trắng” đến từ ba giá trị mặc định. Cả ba đều có trong tài liệu Android Developers.

  1. JavaScript bị tắt. Hướng dẫn WebView cho biết JavaScript bị tắt mặc định trong WebView. Game HTML5 nào cũng cần nó, nên hãy bật trong WebSettings.
  2. Bộ nhớ lưu trữ bị tắt. Tài liệu tham chiếu WebSettings ghi giá trị mặc định của setDomStorageEnabled là false. Game lưu tiến trình trong localStorage cần bật tùy chọn này, nếu không mỗi lần chơi lại bắt đầu từ đầu.
  3. file:// là địa chỉ sai. Hướng dẫn nội dung trong app của Android giải thích rằng URL file:// là origin không rõ ràng (opaque), không dùng được các API như fetch() hay XMLHttpRequest, và khuyên không bật các cách lách quyền truy cập tệp. Trang sản phẩm của chúng tôi cũng nói điều tương tự từ phía game: các phiên bản như Gridspark và Twirldrop không chạy từ file://.

Cách xử lý điểm thứ ba là WebViewAssetLoader trong thư viện AndroidX Webkit. Nó phục vụ tệp trong assets của app qua một địa chỉ HTTPS, và ví dụ của chính Android tải https://appassets.androidplatform.net/assets/index.html. Với game, đó trông như một website bình thường, nên ES module, fetch và bộ nhớ lưu trữ hoạt động như trên máy chủ của bạn.

iOS: WKWebView, tệp cục bộ và kho dữ liệu

Trên iOS, thành phần này là WKWebView. Apple mô tả loadFileURL(_:allowingReadAccessTo:) cho nội dung cục bộ: tham số thứ hai là tệp hoặc thư mục mà WebKit được phép đọc, và truyền vào một thư mục cho phép trang tải các tệp xung quanh.

Vì các phiên bản của chúng tôi không hỗ trợ mở từ file://, hãy thử kỹ hướng này hoặc bỏ qua. Apple còn cung cấp WKURLSchemeHandler, một protocol để tải tài nguyên với các URL scheme mà WebKit không xử lý, nhờ đó app có thể phục vụ thư mục game dưới scheme riêng. Capacitor làm sẵn việc này: scheme mặc định trên iOS của nó là capacitor.

Dữ liệu được lưu trong WKWebsiteDataStore. Trang của Apple cho biết kho mặc định lưu dữ liệu website lâu dài trên ổ đĩa, còn kho không lưu lâu dài chỉ giữ dữ liệu trong bộ nhớ, dành cho duyệt web riêng tư. Nếu ai đó trong đội đặt kho không lưu lâu dài, người chơi sẽ mất tiến trình mỗi lần đóng app.

iOS không có nút quay lại hệ thống, nên màn hình game cần lối thoát riêng: một nút đóng trên thanh native, hoặc một nút mà game gọi qua message handler.

Lưu tiến trình bên trong app

Game của chúng tôi lưu trong bộ nhớ trình duyệt của người chơi, không lưu trên máy chủ. Trang của Solitaire Links và Deepforge ghi rõ: tiến trình được giữ trong localStorage, không có tài khoản hay đồng bộ đám mây. Bên trong app, điều đó dẫn tới ba hệ quả.

  • Địa chỉ là một phần của dữ liệu lưu. Bộ nhớ trình duyệt thuộc về một origin. Nếu bạn chuyển từ scheme hoặc host này sang cái khác, ví dụ từ tên miền thử nghiệm sang appassets.androidplatform.net, người chơi phải bắt đầu lại. Hãy chọn địa chỉ một lần.
  • Khóa lưu là một phần của dữ liệu lưu. Trang sản phẩm Tenguin dặn người mua giữ nguyên khóa lưu trên game đang chạy, nếu không người chơi mất tiến trình. Một số phiên bản TypeScript đặt khóa lưu trữ trong brand.ts. Nếu đổi, hãy đổi có chủ đích, trước khi ra mắt, đừng đổi sau.
  • Xóa dữ liệu app là xóa game. Gỡ cài đặt hoặc xóa bộ nhớ của app sẽ xóa dữ liệu lưu, giống như xóa dữ liệu trình duyệt.

Nếu tiến trình phải theo người dùng qua nhiều thiết bị, đó là tính năng máy chủ mà không phiên bản nào của chúng tôi có. Mọi phiên bản đều ghi lưu đám mây hoặc tài khoản là không bao gồm. Deepforge là điểm bắt đầu dễ nhất: trang của nó mô tả tính năng xuất và nhập dữ liệu lưu trong menu, cùng một API nhỏ window.DeepForge cho phép trang chứa tạm dừng, tiếp tục, đọc dữ liệu lưu và lắng nghe sự kiện lưu.

Xem Deepforge và API cho trang chứa

Nút quay lại, tạm dừng và thoát game

Game HTML5 thường chỉ có một trang. Điều này quan trọng trên Android, nơi nút quay lại đi lùi trong lịch sử của WebView. Hướng dẫn WebView của Android đưa ra mẫu xử lý: kiểm tra canGoBack() rồi gọi goBack(), hoặc để hệ thống xử lý sự kiện; với AndroidX bạn đăng ký cùng logic đó trên OnBackPressedDispatcher. Trong game một trang, lịch sử thường trống, nên nút quay lại sẽ đóng ngay màn hình game, giữa chừng một màn chơi.

Hãy quyết định nút quay lại làm gì và ghi rõ ra:

  • Nhấn lần đầu mở menu tạm dừng của game; nhấn lần hai rời màn hình game.
  • Hoặc nút quay lại luôn thoát, sau khi game đã lưu. Mọi phiên bản đều lưu cục bộ, nhưng hãy kiểm tra thời điểm ghi: cuối màn hay trong lúc chơi.
  • Khi app chuyển xuống nền, hãy tạm dừng game. Không tạm dừng thì bộ đếm giờ vẫn chạy phía sau các màn hình khác của app.

Các phiên bản của chúng tôi không kèm cầu nối với app. Một số có điểm vào từ phía trang: Gridspark và Ricopop có màn hình chạm để bắt đầu và nút toàn màn hình mà bạn bật hoặc tắt trong tệp cấu hình, còn Deepforge cho trang gọi tạm dừng và tiếp tục. Mọi thứ khác, như gửi tin nhắn tới mã native khi hết một màn, là một thay đổi nhỏ trong mã nguồn do đội bạn thêm vào hoặc chúng tôi làm theo báo giá.

Xem Gridspark, JavaScript thuần, không cần build để chơi

Giấy phép: một game, một app và những điều nên hỏi trước

Điều khoản của chúng tôi cấp giấy phép vĩnh viễn, không độc quyền để dùng phiên bản trong một sản phẩm cuối, cho bạn hoặc cho một khách hàng. App của bạn cùng mục game chính là sản phẩm cuối đó. Người chơi có thể truy cập miễn phí hoặc qua mô hình kiếm tiền bằng quảng cáo. Bạn được sửa mã, hình ảnh và âm thanh, và được phép white label: thương hiệu của bạn thay cho thương hiệu của chúng tôi.

Có ba trường hợp cần xem kỹ hơn.

  • Nhiều app. Một agency đưa cùng một game vào ba app của khách hàng cần ba giấy phép. Mua nhiều mẫu trong một đơn được giảm giá theo gói: 5% cho 2 mẫu, 10% cho 3, 15% cho 4 và 20% cho 5 mẫu trở lên.
  • Bản Android và iOS của cùng một app. Một giấy phép cho phép bạn phát hành game đó ở bất cứ đâu, kể cả Google Play và App Store. Vẫn là một giấy phép cho mỗi sản phẩm cuối.
  • SDK game cho các lập trình viên khác. Điều khoản cấm phân phối lại mẫu hoặc mã nguồn bên trong một sản phẩm khác dành cho lập trình viên. Một module game bạn bán cho các nhà làm app khác chính là loại sản phẩm đó.

Nếu app của bạn thu phí cho mục game hoặc bán vật phẩm bên trong, cũng hãy hỏi chúng tôi trước. Điều khoản nêu rõ truy cập miễn phí và kiếm tiền bằng quảng cáo, và một số phiên bản ghi giao dịch bằng tiền thật là không bao gồm. Trên iOS, mục 3.1.1 quy định việc mở khóa tính năng hoặc nội dung, kể cả màn chơi, phải dùng mua hàng trong ứng dụng.

Giấy phép, hóa đơn và báo giá cho doanh nghiệp

Câu hỏi thường gặp

Tôi có thể đưa game HTML5 vào app Android hoặc iOS không?

Có. Tải thư mục game trong một WebView (WebView trên Android, WKWebView trên iOS), đóng gói cùng app hoặc tải từ máy chủ HTTPS của bạn. Bật JavaScript và bộ nhớ lưu trữ, và phục vụ tệp từ một địa chỉ kiểu HTTPS thay vì file://.

Game có chạy offline trong app không?

Chỉ khi bạn đóng gói tệp và phiên bản đó không tải gì từ mạng. Nhiều phiên bản của chúng tôi giữ hình ảnh, âm thanh và font ở cục bộ; trang của Ricopop ghi rằng game cần kết nối. Hãy thử ở chế độ máy bay trước khi hứa.

Người chơi có mất tiến trình khi tôi cập nhật app không?

Không, nếu địa chỉ và khóa lưu giữ nguyên. Dữ liệu lưu nằm trong bộ nhớ của WebView cho origin đó. Đổi scheme, host hoặc khóa lưu trữ sẽ khiến mọi người bắt đầu lại từ đầu.

App của tôi cần bao nhiêu giấy phép?

Mỗi sản phẩm cuối một giấy phép. Một app với một game là một giấy phép; cùng game đó trong app của ba khách hàng là ba. Cùng một app trên Google Play và App Store không cần giấy phép thứ hai: bạn được phát hành game đã cấp phép ở bất cứ đâu.

Bước tiếp theo

Chọn một game, chơi bản demo trên điện thoại, rồi đọc danh sách “Not included in this edition” (không có trong phiên bản này) và chương về lưu dữ liệu trong tài liệu hướng dẫn. Nếu bạn muốn chúng tôi làm màn hình game trong app của bạn, hãy gửi cho chúng tôi app, các nền tảng và game bạn thích, chúng tôi sẽ phản hồi phạm vi, giá và thời gian.

Xem tất cả mẫu game

Yêu cầu báo giá tích hợp vào app