|
const path = require("path"); |
|
const fs = require("fs"); |
|
const xmljs = require("xml-js"); |
|
|
|
/* ======= |
|
* CONFIG |
|
* ======= |
|
*/ |
|
// Add the url's you want to support here. Use the Android's limited glob support as described here: |
|
// https://developer.android.com/guide/topics/manifest/data-element#path |
|
const deeplinkPatterns = [ |
|
"pattern1/.*/", |
|
"pattern2/.*/", |
|
"pattern3/.*/", |
|
"pattern4/.*/", |
|
"pattern5/.*/", |
|
]; |
|
const scheme = "https"; |
|
const host = "www.yourdomain.com"; |
|
|
|
const matchName = (obj, name) => obj.name && obj.name === name; |
|
const hasAttr = (obj, attr) => obj.attributes && obj.attributes[attr]; |
|
const matchAttr = (obj, attr, value) => hasAttr(obj, attr) && obj.attributes[attr] === value; |
|
|
|
function getFirstElementByName(obj, name) { |
|
if (!obj.elements) { |
|
return null; |
|
} |
|
return obj.elements.find(el => matchName(el, name)); |
|
} |
|
|
|
module.exports = function(context) { |
|
const manifestPath = path.join(__dirname, "../platforms/android/app/src/main/AndroidManifest.xml"); |
|
if (!fs.existsSync(manifestPath)) { |
|
throw "AndroidManifest.xml not found"; |
|
} |
|
fs.copyFileSync(manifestPath, manifestPathBackup); |
|
const xml = xmljs.xml2js(fs.readFileSync(manifestPath), { compact: false }); |
|
const manifest = getFirstElementByName(xml, "manifest"); |
|
const application = getFirstElementByName(manifest, "application"); |
|
const mainActivity = application.elements.find(el => |
|
matchName(el, "activity") && |
|
matchAttr(el, "android:name", "MainActivity") |
|
); |
|
|
|
// Cleanup activity |
|
mainActivity.elements = mainActivity.elements.filter(intentFilter => { |
|
if (!intentFilter.name === "intent-filter") { |
|
return true |
|
} |
|
const action = getFirstElementByName(intentFilter, "action"); |
|
if (!action || matchAttr(action, "android:name", "android.intent.action.MAIN")) { |
|
return true; |
|
} |
|
// remove all data elements containing android:pathPrefix attributes |
|
intentFilter.elements = intentFilter.elements.filter(child => { |
|
if (!matchName(child, "data")) { |
|
return true; |
|
} |
|
return !hasAttr(child, "android:pathPrefix") && !hasAttr(child, "android:pathPattern"); |
|
}) |
|
|
|
// if no data-attributes remain, remove the intent-filter alltogether |
|
return intentFilter.elements.find(el => matchName(el, "data")); |
|
}); |
|
|
|
// add our own intent-filter element with proper pattern data |
|
mainActivity.elements.push({ |
|
type: "element", |
|
name: "intent-filter", |
|
attributes: { |
|
"android:autoVerify": "true", |
|
}, |
|
elements: [ |
|
{ |
|
type: "element", |
|
name: "action", |
|
attributes: { |
|
"android:name": "android.intent.action.VIEW" |
|
} |
|
}, |
|
{ |
|
type: "element", |
|
name: "category", |
|
attributes: { |
|
"android:name": "android.intent.category.DEFAULT" |
|
} |
|
}, |
|
{ |
|
type: "element", |
|
name: "category", |
|
attributes: { |
|
"android:name": "android.intent.category.BROWSABLE" |
|
} |
|
}, |
|
...deeplinkPatterns.map(pattern => ({ |
|
type: "element", |
|
name: "data", |
|
attributes: { |
|
"android:host": host, |
|
"android:pathPattern": pattern, |
|
"android:scheme": scheme, |
|
} |
|
})) |
|
] |
|
}) |
|
fs.writeFileSync(manifestPath, xmljs.js2xml(xml, {spaces: 4})) |
|
}; |