如何将 Nuxt js (pwa) 项目转换为 apk?

how to convert Nuxt js (pwa) project to apk?

我正在做一个 nuxt 项目,我想将它添加到 Google Play,但它需要一个 apk 输出 那么有什么解决方案可以从 nuxt 获取 apk 文件吗?

我已经尝试使用 android studio 但没有成功 manifest.json :

{
  "name": "my nuxt app",
  "short_name": "my lovely nuxt app",
  "description": "pwa to apk",
  "icons": [
    {
      "src": "/logo.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/300.png",
      "sizes": "384x384",
      "type": "image/jpg"
    },{
      "src": "/512.jpg",
      "sizes": "512x512",
      "type": "image/jpg"
    }
  ],
  "start_url": "/?standalone=true",
  "display": "standalone",
  "background_color": "#222",
  "theme_color": "#222",
  "lang": "fa",
  "prefer_related_applications": true
}

我在安装时遇到了这个错误:

为了安全起见,您的 phone 已设置为阻止安装

TWA 是一回事,您可以在此处阅读:https://www.ateamsoftsolutions.com/what-are-pwa-and-twa/

同时,这与 .apk 不同,后者与 Web 平台完全不同,如您在此处所见:https://fileinfo.com/extension/apk(none 的扩展名是在网络上使用的)

这是一种完全不同的捆绑语言和生态系统。因此,您不能将 PWA 移植到 Google Play 应用中。

您需要学习使用 Capacitor (Quasar) 或类似解决方案制作移动应用程序的方法。

或者使用 React Native、Flutter 甚至 vanilla Kotlin(后者是最接近机器的)。

除了 kissu 的评论外,我总是对常规网站使用 Nuxt.js,但对移动应用程序使用 Ionic/Vue with Capacitor,它工作得很好,相同的生态系统和很棒的 UI 组件和 CLI 来自离子。这只是对可行的东西的建议,并且它具有最小的学习曲线。

经过如此多的搜索,感谢@kissu 给我关于 twa 的提示,我找到了解决方案:

1.first 你的 nuxt 项目需要一个 service worker 并将其放入 static 文件夹

示例:

/static/sw.js 和 sw.js 的内部:

 const options = {"workboxURL":"https://cdn.jsdelivr.net/npm/workbox-cdn@5.1.4/workbox/workbox-sw.js","importScripts":[],"config":{"debug":false},"cacheOptions":{"cacheId":"online-actor-prod","directoryIndex":"/","revision":"c35hcbL1ctml"},"clientsClaim":true,"skipWaiting":true,"cleanupOutdatedCaches":true,"offlineAnalytics":false,"preCaching":[{"revision":"c35hcbL1ctml","url":"/"}],"runtimeCaching":[{"urlPattern":"/_nuxt/","handler":"CacheFirst","method":"GET","strategyPlugins":[]},{"urlPattern":"/","handler":"NetworkFirst","method":"GET","strategyPlugins":[]}],"offlinePage":null,"pagesURLPattern":"/","offlineStrategy":"NetworkFirst"}

importScripts(...[options.workboxURL, ...options.importScripts])

initWorkbox(workbox, options)
workboxExtensions(workbox, options)
precacheAssets(workbox, options)
cachingExtensions(workbox, options)
runtimeCaching(workbox, options)
offlinePage(workbox, options)
routingExtensions(workbox, options)

function getProp(obj, prop) {
  return prop.split('.').reduce((p, c) => p[c], obj)
}

function initWorkbox(workbox, options) {
  if (options.config) {
    // Set workbox config
    workbox.setConfig(options.config)
  }

  if (options.cacheNames) {
    // Set workbox cache names
    workbox.core.setCacheNameDetails(options.cacheNames)
  }

  if (options.clientsClaim) {
    // Start controlling any existing clients as soon as it activates
    workbox.core.clientsClaim()
  }

  if (options.skipWaiting) {
    workbox.core.skipWaiting()
  }

  if (options.cleanupOutdatedCaches) {
    workbox.precaching.cleanupOutdatedCaches()
  }

  if (options.offlineAnalytics) {
    // Enable offline Google Analytics tracking
    workbox.googleAnalytics.initialize()
  }
}

function precacheAssets(workbox, options) {
  if (options.preCaching.length) {
    workbox.precaching.precacheAndRoute(options.preCaching, options.cacheOptions)
  }
}


function runtimeCaching(workbox, options) {
  const requestInterceptor = {
    requestWillFetch({ request }) {
      if (request.cache === 'only-if-cached' && request.mode === 'no-cors') {
        return new Request(request.url, { ...request, cache: 'default', mode: 'no-cors' })
      }
      return request
    },
    fetchDidFail(ctx) {
      ctx.error.message =
        '[workbox] Network request for ' + ctx.request.url + ' threw an error: ' + ctx.error.message
      console.error(ctx.error, 'Details:', ctx)
    },
    handlerDidError(ctx) {
      ctx.error.message =
        `[workbox] Network handler threw an error: ` + ctx.error.message
      console.error(ctx.error, 'Details:', ctx)
      return null
    }
  }

  for (const entry of options.runtimeCaching) {
    const urlPattern = new RegExp(entry.urlPattern)
    const method = entry.method || 'GET'

    const plugins = (entry.strategyPlugins || [])
      .map(p => new (getProp(workbox, p.use))(...p.config))

    plugins.unshift(requestInterceptor)

    const strategyOptions = { ...entry.strategyOptions, plugins }

    const strategy = new workbox.strategies[entry.handler](strategyOptions)

    workbox.routing.registerRoute(urlPattern, strategy, method)
  }
}

function offlinePage(workbox, options) {
  if (options.offlinePage) {
    // Register router handler for offlinePage
    workbox.routing.registerRoute(new RegExp(options.pagesURLPattern), ({ request, event }) => {
      const strategy = new workbox.strategies[options.offlineStrategy]
      return strategy
        .handle({ request, event })
        .catch(() => caches.match(options.offlinePage))
    })
  }
}

function workboxExtensions(workbox, options) {
  
}

function cachingExtensions(workbox, options) {
  
}

function routingExtensions(workbox, options) {
  
}

2.you 还需要一个清单,为此将此代码放入您的 nuxt.config.js:

export default{
 pwa: {
    manifest: {
      name: 'example name',
      short_name: 'example',
      lang: 'fa',
      theme_color: '#222',
      background_color: '#222',
      start_url: `/`,
      prefer_related_applications: true,
    },
    icon: {
      fileName: 'logo.png'
    },

   },
  }

3.now 一切就绪,可以创建您的 apk,现在您可以在 google 中搜索 pwa to apk 并使用提供这些服务的网站: 我已经尝试过这些网站并且一切正常:

gonative.io 要么 pwabuilder.com