@quasar/app-webpack
Version:
Quasar Framework App CLI with Webpack
202 lines (164 loc) • 5.99 kB
JavaScript
const fs = require('node:fs')
const et = require('elementtree')
const { log, warn } = require('../../utils/logger.js')
const { ensureConsistency } = require('./ensure-consistency.js')
function setFields (root, cfg) {
Object.keys(cfg).forEach(key => {
const el = root.find(key)
const values = cfg[ key ]
const isObject = Object(values) === values
if (!el) {
if (isObject) {
et.SubElement(root, key, values)
}
else {
const entry = et.SubElement(root, key)
entry.text = values
}
}
else {
if (isObject) {
Object.keys(values).forEach(key => {
el.set(key, values[ key ])
})
}
else {
el.text = values
}
}
})
}
module.exports.CordovaConfigFile = class CordovaConfigFile {
#appURL
#tamperedFiles
#filePath
#ctx
prepare (quasarConf) {
const { ctx } = quasarConf
const { appPaths } = ctx
ensureConsistency({ appPaths })
this.#ctx = ctx
this.#filePath = appPaths.resolve.cordova('config.xml')
const doc = et.parse(fs.readFileSync(this.#filePath, 'utf-8'))
this.#appURL = quasarConf.metaConf.APP_URL
this.#tamperedFiles = []
const root = doc.getroot()
const { appPkg } = ctx.pkg
root.set('version', quasarConf.cordova.version || appPkg.version)
if (quasarConf.cordova.androidVersionCode) {
root.set('android-versionCode', quasarConf.cordova.androidVersionCode)
}
setFields(root, {
content: { src: this.#appURL },
description: quasarConf.cordova.description || appPkg.description
})
if (this.#appURL !== 'index.html' && !root.find(`allow-navigation[ ='${ this.#appURL }']`)) {
et.SubElement(root, 'allow-navigation', { href: this.#appURL })
if (quasarConf.devServer.server.type === 'https' && quasarConf.ctx.targetName === 'ios') {
const node = root.find('name')
if (node) {
this.#prepareAppDelegate(node)
this.#prepareWkWebEngine(node)
}
}
}
// needed for QResizeObserver until ResizeObserver Web API is supported by all platforms
if (!root.find('allow-navigation[@href=\'about:*\']')) {
et.SubElement(root, 'allow-navigation', { href: 'about:*' })
}
this.#save(doc)
}
reset () {
if (!this.#appURL || this.#appURL === 'index.html') return
const doc = et.parse(fs.readFileSync(this.#filePath, 'utf-8'))
const root = doc.getroot()
root.find('content').set('src', 'index.html')
const nav = root.find(`allow-navigation[ ='${ this.#appURL }']`)
if (nav) {
root.remove(nav)
}
this.#tamperedFiles.forEach(file => {
file.content = file.originalContent
})
this.#save(doc)
this.#tamperedFiles = []
}
#save (doc) {
const content = doc.write({ indent: 4 })
fs.writeFileSync(this.#filePath, content, 'utf8')
log('Updated Cordova config.xml')
this.#tamperedFiles.forEach(file => {
fs.writeFileSync(file.path, file.content, 'utf8')
log(`Updated ${ file.name }`)
})
}
#prepareAppDelegate (node) {
const appDelegatePath = this.#ctx.appPaths.resolve.cordova(
`platforms/ios/${ node.text }/Classes/AppDelegate.m`
)
if (!fs.existsSync(appDelegatePath)) {
warn()
warn()
warn()
warn()
warn('AppDelegate.m not found. Your App will revoke the devserver\'s SSL certificate.')
warn('Please report the cordova CLI version and cordova-ios package that you are using.')
warn('Also, disable HTTPS from quasar.config file > devServer > server > type: \'https\'')
warn()
warn()
warn()
warn()
}
else {
const tamperedFile = {
name: 'AppDelegate.m',
path: appDelegatePath
}
tamperedFile.originalContent = fs.readFileSync(appDelegatePath, 'utf-8')
// required for allowing devserver's SSL certificate on iOS
if (tamperedFile.originalContent.indexOf('allowsAnyHTTPSCertificateForHost') === -1) {
tamperedFile.content = tamperedFile.originalContent + `
NSURLRequest(DataController)
+ (BOOL)allowsAnyHTTPSCertificateForHost:(NSString *)host
{
return YES;
}
`
this.#tamperedFiles.push(tamperedFile)
}
}
}
#prepareWkWebEngine (node) {
[
'cordova-plugin-ionic-webview',
'cordova-plugin-wkwebview-engine'
].forEach(plugin => {
const wkWebViewEnginePath = this.#ctx.appPaths.resolve.cordova(
`platforms/ios/${ node.text }/Plugins/${ plugin }/CDVWKWebViewEngine.m`
)
if (fs.existsSync(wkWebViewEnginePath)) {
const tamperedFile = {
name: `${ plugin } > CDVWKWebViewEngine.m`,
path: wkWebViewEnginePath
}
tamperedFile.originalContent = fs.readFileSync(wkWebViewEnginePath, 'utf-8')
// Credit: https://gist.github.com/PeterStegnar/63cb8c9a39a13265c3a855e24a33ca37#file-cdvwkwebviewengine-m-L68-L74
// Enables untrusted SSL connection
if (tamperedFile.originalContent.indexOf('SecTrustRef serverTrust = challenge.protectionSpace.serverTrust') === -1) {
const lookupString = '@implementation CDVWKWebViewEngine'
const insertIndex = tamperedFile.originalContent.indexOf(lookupString) + lookupString.length
tamperedFile.content = tamperedFile.originalContent.substring(0, insertIndex) + `
- (void)webView:(WKWebView *)webView
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {
SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:serverTrust]);
}
` + tamperedFile.originalContent.substring(insertIndex)
this.#tamperedFiles.push(tamperedFile)
}
}
})
}
}