Ionic/Cordova: добавьте фильтр намерений с помощью config.xml

Я разрабатываю мобильное приложение с использованием Ionic Framework (на основе Кордовы).

В Android я зарегистрирую свое приложение, чтобы открыть *.txt файлы. Я делаю это, добавляя фильтр намерений в platform/android/AndroidManifest.xml, и он работает. Но папка платформы находится в .gitignore: я хочу сделать это с помощью config.xml.

Я попытался добавить в config.xml:

 <platform name="android">
    <config-file target="AndroidManifest.xml" parent="/*/application/activity">
      <intent-filter><!-- ... --></intent-filter>
    </config-file>
    <!-- ... -->
 </platform>

И я попробовал добавить:

 <platform name="android">
    <config-file target="AndroidManifest.xml" parent="/manifest/application">
      <activity android:name="CordovaApp"> 
        <intent-filter><!-- ... --></intent-filter>
      </activity>
    </config-file>
    <!-- ... -->
 </platform>

Затем я попытался обновить запуск AndroidManifest

ionic prepare

Или также:

ionic remove platform android && ionic add platform android

Но AndroidManifest.xml всегда неизменен. Что я делаю неправильно?

Я использую Ionic 1.3.2 и Cordova 4.2.0.

Edit Здесь весь config.xml:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<widget id="com.ionicframework.myapp551932" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0" xmlns:android="http://schemas.android.com/apk/res/android">
  <name>MyApp</name>
  <description>
        myApp
    </description>
  <author email="[email protected]" href="#" onclick="location.href='http://www.example.com/'; return false;">
      A Team
    </author>
  <content src="index.html"/>
  <access origin="*"/>
  <preference name="webviewbounce" value="false"/>
  <preference name="UIWebViewBounce" value="false"/>
  <preference name="DisallowOverscroll" value="true"/>
  <preference name="BackupWebStorage" value="none"/>
  <preference name="SplashScreen" value="screen"/>
  <preference name="SplashScreenDelay" value="3000"/>
  <feature name="StatusBar">
    <param name="ios-package" value="CDVStatusBar" onload="true"/>
  </feature>
  <platform name="android">
    <config-file target="AndroidManifest.xml" parent="/manifest/application/activity">
      <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="file" />
        <data android:mimeType="*/*" />
        <data android:pathPattern=".*\\.txt" />
        <data android:host="*" />
      </intent-filter>
      <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:scheme="content" />
        <data android:pathPattern=".*\\.txt" />
        <data android:mimeType="*/*" />
      </intent-filter>
    </config-file>
    <icon src="resources/android/icon/drawable-ldpi-icon.png" density="ldpi"/>
    <icon src="resources/android/icon/drawable-mdpi-icon.png" density="mdpi"/>
    <icon src="resources/android/icon/drawable-hdpi-icon.png" density="hdpi"/>
    <icon src="resources/android/icon/drawable-xhdpi-icon.png" density="xhdpi"/>
    <icon src="resources/android/icon/drawable-xxhdpi-icon.png" density="xxhdpi"/>
    <icon src="resources/android/icon/drawable-xxxhdpi-icon.png" density="xxxhdpi"/>
    <splash src="resources/android/splash/drawable-land-ldpi-screen.png" density="land-ldpi"/>
    <splash src="resources/android/splash/drawable-land-mdpi-screen.png" density="land-mdpi"/>
    <splash src="resources/android/splash/drawable-land-hdpi-screen.png" density="land-hdpi"/>
    <splash src="resources/android/splash/drawable-land-xhdpi-screen.png" density="land-xhdpi"/>
    <splash src="resources/android/splash/drawable-land-xxhdpi-screen.png" density="land-xxhdpi"/>
    <splash src="resources/android/splash/drawable-land-xxxhdpi-screen.png" density="land-xxxhdpi"/>
    <splash src="resources/android/splash/drawable-port-ldpi-screen.png" density="port-ldpi"/>
    <splash src="resources/android/splash/drawable-port-mdpi-screen.png" density="port-mdpi"/>
    <splash src="resources/android/splash/drawable-port-hdpi-screen.png" density="port-hdpi"/>
    <splash src="resources/android/splash/drawable-port-xhdpi-screen.png" density="port-xhdpi"/>
    <splash src="resources/android/splash/drawable-port-xxhdpi-screen.png" density="port-xxhdpi"/>
    <splash src="resources/android/splash/drawable-port-xxxhdpi-screen.png" density="port-xxxhdpi"/>
  </platform>
  <icon src="resources/android/icon/drawable-xhdpi-icon.png"/>
</widget>

Ответ 1

Cordova 9 теперь напрямую поддерживает использование разделов <config-file> и <edit-config>, как в файлах plugin.xml.

Без использования какого-либо плагина или перехватчика вы можете напрямую сделать следующее, например, чтобы добавить фильтр намерений в AndroidManifest.xml:

<?xml version='1.0' encoding='utf-8'?>
<widget id="yourdomain.app" version="1.7.8" xmlns="http://www.w3.org/ns/widgets" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:cdv="http://cordova.apache.org/ns/1.0">
    <!-- ... -->
    <platform name="android">
        <!-- ... -->
        <config-file parent="application" target="AndroidManifest.xml">
            <activity android:label="webIntentFilter" android:name="yourdomain.app">
                <intent-filter android:autoVerify="true">
                    <action android:name="android.intent.action.VIEW" />
                    <category android:name="android.intent.category.DEFAULT" />
                    <category android:name="android.intent.category.BROWSABLE" />
                    <data android:host="yourdomain.com" android:scheme="https" />
                </intent-filter>
            </activity>
        </config-file>
    </platform>
    <!-- ... -->
</widget>

Не забудьте добавить атрибут xmlns:android="http://schemas.android.com/apk/res/android" в тег <widget>, чтобы избежать ошибки unbound prefix при сборке.

Ответ 2

Решено!

Я не могу сделать это с помощью Ionic или Cordova: это функция PhoneGap (см. этот fooobar.com/questions/451124/...)

Я могу сделать это двумя другими способами:

  1. Использование собственного плагина Cordova
  2. Использование крючка

Я предпочел второй путь. Я нашел интересный крючок для своих целей. Примечание. Не забудьте установить некоторые пакеты:

npm install lodash elementtree plist --save-dev

К сожалению, этот крючок объединяет теги. Поэтому я написал немного измененную версию этого хука: смотрите здесь. Вы можете поместить этот хук в /hooks/after_platform_add.

Теперь у меня есть конфигурация фильтра намерений в config.xml:

  <platform name="android">
    <config-file target="AndroidManifest.xml" parent="application/activity">
      <intent-filter><!-- ... --></intent-filter>
    </config-file>
    <!-- ... -->
  </platform>

И я могу обновить AndroidManifest.xml регенерирующую платформу Android:

ionic platform remove android && ionic platform add android

Ответ 3

У меня была та же проблема, но идея установить (а затем запомнить или задокументировать зависимость) кучу зависимостей нпм, а затем использовать большой универсальный крючок была слишком тяжелой для того, что мне было нужно.

Крюками могут быть простые сценарии оболочки, которые часто являются гораздо более простым способом изменения текстовых файлов. В моем случае мне нужно было добавить фильтр-намерение в действие MainActivity, которое является тривиальным заданием для sed; Я только что создал файл hooks/after_prepare/020_add_moozvine_intents.sh с содержимым:

#!/usr/bin/env zsh

MANIFEST=${0:h}/../../platforms/android/AndroidManifest.xml
[[ -e $MANIFEST ]] || { print "Manifest not found at $MANIFEST." ; exit 1; }

grep -q HANDLE_MOOZVINE_NOTIFICATION $MANIFEST && { print "Manifest already modified. Nothing to do."; exit 0; }

AFTER_LINE='android:name="MainActivity"'
ADDITION='\
        <intent-filter>\
            <action android:name="HANDLE_MOOZVINE_NOTIFICATION" />\
            <category android:name="android.intent.category.DEFAULT" />\
        </intent-filter>
';

sed -i -e "/${AFTER_LINE}/a${ADDITION}" $MANIFEST

Работа выполнена. Вы можете использовать аналогичный подход для любых простых текстовых модификаций сгенерированных файлов.

Ответ 4

Вот приведенное выше решение Rich написано в JS для будущих Googlers, поскольку у меня были проблемы с оболочкой script.

module.exports = function (context) {
    const fs = require('fs');
    const _ = require('lodash');

    const scheme = 'flowkey';
    const insertIntent = `
    <intent-filter>
                <action android:name="android.intent.action.VIEW"></action>
                <category android:name="android.intent.category.DEFAULT"></category>
                <category android:name="android.intent.category.BROWSABLE"></category>
                <data android:scheme="${scheme}"></data>
    </intent-filter>
    `;
    const manifestPath = context.opts.projectRoot + '/platforms/android/AndroidManifest.xml';
    const androidManifest = fs.readFileSync(manifestPath).toString();
    if (!androidManifest.includes(`android:scheme="${scheme}"`)) {
        const manifestLines = androidManifest.split(/\r?\n/);
        const lineNo = _.findIndex(manifestLines, (line) => line.includes('@string/activity_name'));
        manifestLines.splice(lineNo + 1, 0, insertIntent);
        fs.writeFileSync(manifestPath, manifestLines.join('\n'));
    }
};

Используйте это как ваш крюк для подготовки.

Примечание: это в ES6, здесь вы можете найти версию ES5: https://gist.github.com/smowden/f863331034bf300b960beef1ae25bf82