不同 activity 上的 Cordova 通用链接

Cordova universal links on a different activity

我正在我的 Cordova 应用程序中实施 Firebase 身份验证。 android 应用程序将 Cordova 集成到 activity 而不是 main/launcher activity。因此,所需的依赖插件 "cordova-universal-links-plugin" 没有以正确的 activity 为目标(它以 main/launcher activity 为目标)。

有没有办法为通用链接指定目标 activity?如果没有,我如何制作 workaround/hack 来解决这个问题(因为插件不再维护)?

没有为 cordova-universal-links-plugin 指定目标 activity 的已知方法。您可以通过 运行ning 脚本 before/after cordova prepare.

创建解决方法

修复将像这样工作:

  1. 您必须重新安排 AndroidManifest.xml 中的活动,以便目标 activity 排在 main/launcher activity 之前。我假设目标 activity 最初看起来像这样:
<activity android:name=".CordovaActivity">
  <intent-filter android:label="@string/launcher_name">
    <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
</activity>
  1. 现在,您将编写两个 NodeJS 脚本:before_prepare.jsafter_prepare.js

    a) before_prepare.js:这将在目标 activity 的 <category /> 标签后添加一个 <action android:name="android.intent.action.VIEW" />。由于 "CordovaActivity" 暂时也是一个 main/launcher activity & 在实际主要 activity 之前,通用链接插件应该以它为目标。

    b) after_prepare.js:我们希望在插件将 universal-links intent-filters 应用到您的目标 activity 之后 运行。它将删除您添加的 <action /> 标签。这是必要的,因为 Android 不能允许两个主要活动。

  2. before_prepare.js 作为 before_prepare Cordova 挂钩添加到您的项目级别 config.xml

  3. 因为 Cordova 运行 是插件挂钩之前的挂钩,所以您不能将 after_prepare.js 添加为 after_prepare Cordova 挂钩。那是因为 <action /> 标签会在通用链接插件有机会 运行 之前被删除。相反,您必须在 cordova prepare 命令之后 运行 它。我建议使用 cordova prepare.

  4. 之后 运行s after_prepare.js 的 npm 脚本 (npm run prepare) 来执行此操作

我的实现依赖于 elementtree 进行 XML 编辑(它也被 Cordova 内部使用):

npm install elementtree

before_prepare.js:

const et = require('elementtree')
const fs = require('fs')

const MANIFEST_FILE = '/.../CordovaProject/platforms/android/app/src/main/AndroidManifest.xml'

/**
 * Add main action intent from `SurkartaActivity`.
 *
 * @param {ElementTree} manifestTree
 */
function addMainAction (manifestTree) {
    const intentFilterElement = manifestTree.find("./application/activity[@android:name='.SurakartaActivity']")
        .getchildren()[0]

    const mainActionElement = et.SubElement(intentFilterElement, 'action')
    mainActionElement.set('android:name', 'android.intent.action.MAIN')
}

// Cordova hook executes module.exports
module.exports = function () {
    const manifestTree = et.parse(fs.readFileSync(MANIFEST_FILE, 'utf8'))
    addMainAction(manifestTree)

    console.log(manifestTree.write())
    fs.writeFileSync(MANIFEST_FILE, manifestTree.write())
}

after_prepare.js:

const et = require('elementtree')
const fs = require('fs')

const MANIFEST_FILE = '/.../CordovaProject/platforms/android/app/src/main/AndroidManifest.xml'

/**
 * Remove main action intent from `SurkartaActivity`.
 *
 * @param {ElementTree} manifestTree
 */
function stripMainAction (manifestTree) {
    const intentFilterElement = manifestTree.find("./application/activity[@android:name='.SurakartaActivity']")
        .getchildren()[0]
    intentFilterElement.remove(intentFilterElement.getchildren()[1])
}

function hey () {
    const manifestTree = et.parse(fs.readFileSync(MANIFEST_FILE, 'utf8'))
    stripMainAction(manifestTree)
    fs.writeFileSync(MANIFEST_FILE, manifestTree.write())
}

module.exports = hey

// This isn't an Cordova hook, so run it manually
hey()

对现有文件的更改:

config.xml:

<hook type="before_prepare" src="./path/to/before_prepare.js" />

package.json:

{
  "scripts": {
    "prepare": "cordova prepare; node ./path/to/after_prepare.js"
  },
  "dependencies": {
    "elementtree": "@latest" /* npm install elementtree should do this for you */
  }
}