Update capacitor version

This commit is contained in:
Pieter Vander Vennet 2025-07-06 20:20:48 +02:00
parent 91155bce0a
commit f3b3a86b32
610 changed files with 28718 additions and 7101 deletions

View file

@ -1,19 +1,19 @@
ext { ext {
androidxActivityVersion = project.hasProperty('androidxActivityVersion') ? rootProject.ext.androidxActivityVersion : '1.8.0' androidxActivityVersion = project.hasProperty('androidxActivityVersion') ? rootProject.ext.androidxActivityVersion : '1.9.2'
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.6.1' androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.0'
androidxCoordinatorLayoutVersion = project.hasProperty('androidxCoordinatorLayoutVersion') ? rootProject.ext.androidxCoordinatorLayoutVersion : '1.2.0' androidxCoordinatorLayoutVersion = project.hasProperty('androidxCoordinatorLayoutVersion') ? rootProject.ext.androidxCoordinatorLayoutVersion : '1.2.0'
androidxCoreVersion = project.hasProperty('androidxCoreVersion') ? rootProject.ext.androidxCoreVersion : '1.12.0' androidxCoreVersion = project.hasProperty('androidxCoreVersion') ? rootProject.ext.androidxCoreVersion : '1.15.0'
androidxFragmentVersion = project.hasProperty('androidxFragmentVersion') ? rootProject.ext.androidxFragmentVersion : '1.6.2' androidxFragmentVersion = project.hasProperty('androidxFragmentVersion') ? rootProject.ext.androidxFragmentVersion : '1.8.4'
androidxWebkitVersion = project.hasProperty('androidxWebkitVersion') ? rootProject.ext.androidxWebkitVersion : '1.9.0' androidxWebkitVersion = project.hasProperty('androidxWebkitVersion') ? rootProject.ext.androidxWebkitVersion : '1.12.1'
junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.5' androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.2.1'
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.5.1' androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.6.1'
cordovaAndroidVersion = project.hasProperty('cordovaAndroidVersion') ? rootProject.ext.cordovaAndroidVersion : '10.1.1' cordovaAndroidVersion = project.hasProperty('cordovaAndroidVersion') ? rootProject.ext.cordovaAndroidVersion : '10.1.1'
} }
buildscript { buildscript {
ext.kotlin_version = project.hasProperty("kotlin_version") ? rootProject.ext.kotlin_version : '1.9.10' ext.kotlin_version = project.hasProperty("kotlin_version") ? rootProject.ext.kotlin_version : '1.9.25'
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
@ -22,7 +22,7 @@ buildscript {
} }
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:8.2.1' classpath 'com.android.tools.build:gradle:8.7.2'
if (System.getenv("CAP_PUBLISH") == "true") { if (System.getenv("CAP_PUBLISH") == "true") {
classpath 'io.github.gradle-nexus:publish-plugin:1.3.0' classpath 'io.github.gradle-nexus:publish-plugin:1.3.0'
@ -42,10 +42,10 @@ if (System.getenv("CAP_PUBLISH") == "true") {
android { android {
namespace "com.getcapacitor.android" namespace "com.getcapacitor.android"
compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 34 compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 35
defaultConfig { defaultConfig {
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22 minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 23
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 34 targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 35
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"
consumerProguardFiles 'proguard-rules.pro' consumerProguardFiles 'proguard-rules.pro'
@ -64,8 +64,8 @@ android {
lintConfig file('lint.xml') lintConfig file('lint.xml')
} }
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_17 sourceCompatibility JavaVersion.VERSION_21
targetCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_21
} }
publishing { publishing {
singleVariant("release") singleVariant("release")
@ -90,7 +90,7 @@ dependencies {
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
implementation "org.apache.cordova:framework:$cordovaAndroidVersion" implementation "org.apache.cordova:framework:$cordovaAndroidVersion"
testImplementation 'org.json:json:20231013' testImplementation 'org.json:json:20240303'
testImplementation 'org.mockito:mockito-inline:5.2.0' testImplementation 'org.mockito:mockito-core:5.14.1'
} }

View file

@ -142,9 +142,7 @@ var nativeBridge = (function (exports) {
const CAPACITOR_HTTP_INTERCEPTOR = '/_capacitor_http_interceptor_'; const CAPACITOR_HTTP_INTERCEPTOR = '/_capacitor_http_interceptor_';
const CAPACITOR_HTTP_INTERCEPTOR_URL_PARAM = 'u'; const CAPACITOR_HTTP_INTERCEPTOR_URL_PARAM = 'u';
// TODO: export as Cap function // TODO: export as Cap function
const isRelativeOrProxyUrl = (url) => !url || const isRelativeOrProxyUrl = (url) => !url || !(url.startsWith('http:') || url.startsWith('https:')) || url.indexOf(CAPACITOR_HTTP_INTERCEPTOR) > -1;
!(url.startsWith('http:') || url.startsWith('https:')) ||
url.indexOf(CAPACITOR_HTTP_INTERCEPTOR) > -1;
// TODO: export as Cap function // TODO: export as Cap function
const createProxyUrl = (url, win) => { const createProxyUrl = (url, win) => {
var _a, _b; var _a, _b;
@ -174,11 +172,10 @@ var nativeBridge = (function (exports) {
return webviewServerUrl + '/_capacitor_file_' + filePath; return webviewServerUrl + '/_capacitor_file_' + filePath;
} }
else if (filePath.startsWith('file://')) { else if (filePath.startsWith('file://')) {
return (webviewServerUrl + filePath.replace('file://', '/_capacitor_file_')); return webviewServerUrl + filePath.replace('file://', '/_capacitor_file_');
} }
else if (filePath.startsWith('content://')) { else if (filePath.startsWith('content://')) {
return (webviewServerUrl + return webviewServerUrl + filePath.replace('content:/', '/_capacitor_content_');
filePath.replace('content:/', '/_capacitor_content_'));
} }
} }
return filePath; return filePath;
@ -289,9 +286,6 @@ var nativeBridge = (function (exports) {
return docAddEventListener.apply(doc, args); return docAddEventListener.apply(doc, args);
}; };
} }
// deprecated in v3, remove from v4
cap.platform = cap.getPlatform();
cap.isNative = cap.isNativePlatform();
win.Capacitor = cap; win.Capacitor = cap;
}; };
const initVendor = (win, cap) => { const initVendor = (win, cap) => {
@ -321,27 +315,14 @@ var nativeBridge = (function (exports) {
win.Ionic.WebView = IonicWebView; win.Ionic.WebView = IonicWebView;
}; };
const initLogger = (win, cap) => { const initLogger = (win, cap) => {
const BRIDGED_CONSOLE_METHODS = [ const BRIDGED_CONSOLE_METHODS = ['debug', 'error', 'info', 'log', 'trace', 'warn'];
'debug',
'error',
'info',
'log',
'trace',
'warn',
];
const createLogFromNative = (c) => (result) => { const createLogFromNative = (c) => (result) => {
if (isFullConsole(c)) { if (isFullConsole(c)) {
const success = result.success === true; const success = result.success === true;
const tagStyles = success const tagStyles = success
? 'font-style: italic; font-weight: lighter; color: gray' ? 'font-style: italic; font-weight: lighter; color: gray'
: 'font-style: italic; font-weight: lighter; color: red'; : 'font-style: italic; font-weight: lighter; color: red';
c.groupCollapsed('%cresult %c' + c.groupCollapsed('%cresult %c' + result.pluginId + '.' + result.methodName + ' (#' + result.callbackId + ')', tagStyles, 'font-style: italic; font-weight: bold; color: #444');
result.pluginId +
'.' +
result.methodName +
' (#' +
result.callbackId +
')', tagStyles, 'font-style: italic; font-weight: bold; color: #444');
if (result.success === false) { if (result.success === false) {
c.error(result.error); c.error(result.error);
} }
@ -361,13 +342,7 @@ var nativeBridge = (function (exports) {
}; };
const createLogToNative = (c) => (call) => { const createLogToNative = (c) => (call) => {
if (isFullConsole(c)) { if (isFullConsole(c)) {
c.groupCollapsed('%cnative %c' + c.groupCollapsed('%cnative %c' + call.pluginId + '.' + call.methodName + ' (#' + call.callbackId + ')', 'font-weight: lighter; color: gray', 'font-weight: bold; color: #000');
call.pluginId +
'.' +
call.methodName +
' (#' +
call.callbackId +
')', 'font-weight: lighter; color: gray', 'font-weight: bold; color: #000');
c.dir(call); c.dir(call);
c.groupEnd(); c.groupEnd();
} }
@ -379,9 +354,7 @@ var nativeBridge = (function (exports) {
if (!c) { if (!c) {
return false; return false;
} }
return (typeof c.groupCollapsed === 'function' || return typeof c.groupCollapsed === 'function' || typeof c.groupEnd === 'function' || typeof c.dir === 'function';
typeof c.groupEnd === 'function' ||
typeof c.dir === 'function');
}; };
const serializeConsoleMessage = (msg) => { const serializeConsoleMessage = (msg) => {
try { try {
@ -440,9 +413,7 @@ var nativeBridge = (function (exports) {
set: function (val) { set: function (val) {
const cookiePairs = val.split(';'); const cookiePairs = val.split(';');
const domainSection = val.toLowerCase().split('domain=')[1]; const domainSection = val.toLowerCase().split('domain=')[1];
const domain = cookiePairs.length > 1 && const domain = cookiePairs.length > 1 && domainSection != null && domainSection.length > 0
domainSection != null &&
domainSection.length > 0
? domainSection.split(';')[0].trim() ? domainSection.split(';')[0].trim()
: ''; : '';
if (platform === 'ios') { if (platform === 'ios') {
@ -497,6 +468,15 @@ var nativeBridge = (function (exports) {
if (doPatchHttp) { if (doPatchHttp) {
// fetch patch // fetch patch
window.fetch = async (resource, options) => { window.fetch = async (resource, options) => {
const headers = new Headers(options === null || options === void 0 ? void 0 : options.headers);
const contentType = headers.get('Content-Type') || headers.get('content-type');
if ((options === null || options === void 0 ? void 0 : options.body) instanceof FormData &&
(contentType === null || contentType === void 0 ? void 0 : contentType.includes('multipart/form-data')) &&
!contentType.includes('boundary')) {
headers.delete('Content-Type');
headers.delete('content-type');
options.headers = headers;
}
const request = new Request(resource, options); const request = new Request(resource, options);
if (request.url.startsWith(`${cap.getServerUrl()}/`)) { if (request.url.startsWith(`${cap.getServerUrl()}/`)) {
return win.CapacitorWebFetch(resource, options); return win.CapacitorWebFetch(resource, options);
@ -506,6 +486,17 @@ var nativeBridge = (function (exports) {
method.toLocaleUpperCase() === 'HEAD' || method.toLocaleUpperCase() === 'HEAD' ||
method.toLocaleUpperCase() === 'OPTIONS' || method.toLocaleUpperCase() === 'OPTIONS' ||
method.toLocaleUpperCase() === 'TRACE') { method.toLocaleUpperCase() === 'TRACE') {
// a workaround for following android webview issue:
// https://issues.chromium.org/issues/40450316
// Sets the user-agent header to a custom value so that its not stripped
// on its way to the native layer
if (platform === 'android' && (options === null || options === void 0 ? void 0 : options.headers)) {
const userAgent = headers.get('User-Agent') || headers.get('user-agent');
if (userAgent !== null) {
headers.set('x-cap-user-agent', userAgent);
options.headers = headers;
}
}
if (typeof resource === 'string') { if (typeof resource === 'string') {
return await win.CapacitorWebFetch(createProxyUrl(resource, win), options); return await win.CapacitorWebFetch(createProxyUrl(resource, win), options);
} }
@ -519,16 +510,24 @@ var nativeBridge = (function (exports) {
try { try {
const { body } = request; const { body } = request;
const optionHeaders = Object.fromEntries(request.headers.entries()); const optionHeaders = Object.fromEntries(request.headers.entries());
const { data: requestData, type, headers, } = await convertBody((options === null || options === void 0 ? void 0 : options.body) || body || undefined, optionHeaders['Content-Type'] || optionHeaders['content-type']); const { data: requestData, type, headers: requestHeaders, } = await convertBody((options === null || options === void 0 ? void 0 : options.body) || body || undefined, optionHeaders['Content-Type'] || optionHeaders['content-type']);
const nativeHeaders = Object.assign(Object.assign({}, requestHeaders), optionHeaders);
if (platform === 'android') {
if (headers.has('User-Agent')) {
nativeHeaders['User-Agent'] = headers.get('User-Agent');
}
if (headers.has('user-agent')) {
nativeHeaders['user-agent'] = headers.get('user-agent');
}
}
const nativeResponse = await cap.nativePromise('CapacitorHttp', 'request', { const nativeResponse = await cap.nativePromise('CapacitorHttp', 'request', {
url: request.url, url: request.url,
method: method, method: method,
data: requestData, data: requestData,
dataType: type, dataType: type,
headers: Object.assign(Object.assign({}, headers), optionHeaders), headers: nativeHeaders,
}); });
const contentType = nativeResponse.headers['Content-Type'] || const contentType = nativeResponse.headers['Content-Type'] || nativeResponse.headers['content-type'];
nativeResponse.headers['content-type'];
let data = (contentType === null || contentType === void 0 ? void 0 : contentType.startsWith('application/json')) let data = (contentType === null || contentType === void 0 ? void 0 : contentType.startsWith('application/json'))
? JSON.stringify(nativeResponse.data) ? JSON.stringify(nativeResponse.data)
: nativeResponse.data; : nativeResponse.data;
@ -570,8 +569,7 @@ var nativeBridge = (function (exports) {
}, },
}); });
const prototype = win.CapacitorWebXMLHttpRequest.prototype; const prototype = win.CapacitorWebXMLHttpRequest.prototype;
const isProgressEventAvailable = () => typeof ProgressEvent !== 'undefined' && const isProgressEventAvailable = () => typeof ProgressEvent !== 'undefined' && ProgressEvent.prototype instanceof Event;
ProgressEvent.prototype instanceof Event;
// XHR patch abort // XHR patch abort
prototype.abort = function () { prototype.abort = function () {
if (isRelativeOrProxyUrl(this._url)) { if (isRelativeOrProxyUrl(this._url)) {
@ -619,6 +617,13 @@ var nativeBridge = (function (exports) {
}; };
// XHR patch set request header // XHR patch set request header
prototype.setRequestHeader = function (header, value) { prototype.setRequestHeader = function (header, value) {
// a workaround for the following android web view issue:
// https://issues.chromium.org/issues/40450316
// Sets the user-agent header to a custom value so that its not stripped
// on its way to the native layer
if (platform === 'android' && (header === 'User-Agent' || header === 'user-agent')) {
header = 'x-cap-user-agent';
}
if (isRelativeOrProxyUrl(this._url)) { if (isRelativeOrProxyUrl(this._url)) {
return win.CapacitorWebXMLHttpRequest.setRequestHeader.call(this, header, value); return win.CapacitorWebXMLHttpRequest.setRequestHeader.call(this, header, value);
} }
@ -652,9 +657,7 @@ var nativeBridge = (function (exports) {
}, },
}); });
convertBody(body).then(({ data, type, headers }) => { convertBody(body).then(({ data, type, headers }) => {
const otherHeaders = this._headers != null && Object.keys(this._headers).length > 0 const otherHeaders = this._headers != null && Object.keys(this._headers).length > 0 ? this._headers : undefined;
? this._headers
: undefined;
// intercept request & pass to the bridge // intercept request & pass to the bridge
cap cap
.nativePromise('CapacitorHttp', 'request', { .nativePromise('CapacitorHttp', 'request', {
@ -678,8 +681,7 @@ var nativeBridge = (function (exports) {
} }
this._headers = nativeResponse.headers; this._headers = nativeResponse.headers;
this.status = nativeResponse.status; this.status = nativeResponse.status;
if (this.responseType === '' || if (this.responseType === '' || this.responseType === 'text') {
this.responseType === 'text') {
this.response = this.response =
typeof nativeResponse.data !== 'string' typeof nativeResponse.data !== 'string'
? JSON.stringify(nativeResponse.data) ? JSON.stringify(nativeResponse.data)
@ -688,8 +690,7 @@ var nativeBridge = (function (exports) {
else { else {
this.response = nativeResponse.data; this.response = nativeResponse.data;
} }
this.responseText = ((_a = (nativeResponse.headers['Content-Type'] || this.responseText = ((_a = (nativeResponse.headers['Content-Type'] || nativeResponse.headers['content-type'])) === null || _a === void 0 ? void 0 : _a.startsWith('application/json'))
nativeResponse.headers['content-type'])) === null || _a === void 0 ? void 0 : _a.startsWith('application/json'))
? JSON.stringify(nativeResponse.data) ? JSON.stringify(nativeResponse.data)
: nativeResponse.data; : nativeResponse.data;
this.responseURL = nativeResponse.url; this.responseURL = nativeResponse.url;
@ -805,7 +806,7 @@ var nativeBridge = (function (exports) {
}; };
cap.logToNative = createLogToNative(win.console); cap.logToNative = createLogToNative(win.console);
cap.logFromNative = createLogFromNative(win.console); cap.logFromNative = createLogFromNative(win.console);
cap.handleError = err => win.console.error(err); cap.handleError = (err) => win.console.error(err);
win.Capacitor = cap; win.Capacitor = cap;
}; };
function initNativeBridge(win) { function initNativeBridge(win) {
@ -814,7 +815,7 @@ var nativeBridge = (function (exports) {
const callbacks = new Map(); const callbacks = new Map();
const webviewServerUrl = typeof win.WEBVIEW_SERVER_URL === 'string' ? win.WEBVIEW_SERVER_URL : ''; const webviewServerUrl = typeof win.WEBVIEW_SERVER_URL === 'string' ? win.WEBVIEW_SERVER_URL : '';
cap.getServerUrl = () => webviewServerUrl; cap.getServerUrl = () => webviewServerUrl;
cap.convertFileSrc = filePath => convertFileSrcServerUrl(webviewServerUrl, filePath); cap.convertFileSrc = (filePath) => convertFileSrcServerUrl(webviewServerUrl, filePath);
// Counter of callback ids, randomized to avoid // Counter of callback ids, randomized to avoid
// any issues during reloads if a call comes back with // any issues during reloads if a call comes back with
// an existing callback id from an old session // an existing callback id from an old session
@ -823,12 +824,12 @@ var nativeBridge = (function (exports) {
const isNativePlatform = () => true; const isNativePlatform = () => true;
const getPlatform = () => getPlatformId(win); const getPlatform = () => getPlatformId(win);
cap.getPlatform = getPlatform; cap.getPlatform = getPlatform;
cap.isPluginAvailable = name => Object.prototype.hasOwnProperty.call(cap.Plugins, name); cap.isPluginAvailable = (name) => Object.prototype.hasOwnProperty.call(cap.Plugins, name);
cap.isNativePlatform = isNativePlatform; cap.isNativePlatform = isNativePlatform;
// create the postToNative() fn if needed // create the postToNative() fn if needed
if (getPlatformId(win) === 'android') { if (getPlatformId(win) === 'android') {
// android platform // android platform
postToNative = data => { postToNative = (data) => {
var _a; var _a;
try { try {
win.androidBridge.postMessage(JSON.stringify(data)); win.androidBridge.postMessage(JSON.stringify(data));
@ -840,7 +841,7 @@ var nativeBridge = (function (exports) {
} }
else if (getPlatformId(win) === 'ios') { else if (getPlatformId(win) === 'ios') {
// ios platform // ios platform
postToNative = data => { postToNative = (data) => {
var _a; var _a;
try { try {
data.type = data.type ? data.type : 'message'; data.type = data.type ? data.type : 'message';
@ -885,8 +886,7 @@ var nativeBridge = (function (exports) {
if (typeof postToNative === 'function') { if (typeof postToNative === 'function') {
let callbackId = '-1'; let callbackId = '-1';
if (storedCallback && if (storedCallback &&
(typeof storedCallback.callback === 'function' || (typeof storedCallback.callback === 'function' || typeof storedCallback.resolve === 'function')) {
typeof storedCallback.resolve === 'function')) {
// store the call for later lookup // store the call for later lookup
callbackId = String(++callbackIdCount); callbackId = String(++callbackIdCount);
callbacks.set(callbackId, storedCallback); callbacks.set(callbackId, storedCallback);
@ -921,7 +921,7 @@ var nativeBridge = (function (exports) {
/** /**
* Process a response from the native layer. * Process a response from the native layer.
*/ */
cap.fromNative = result => { cap.fromNative = (result) => {
returnResult(result); returnResult(result);
}; };
const returnResult = (result) => { const returnResult = (result) => {

View file

@ -15,7 +15,11 @@ import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.webkit.ServiceWorkerClient;
import android.webkit.ServiceWorkerController;
import android.webkit.ValueCallback; import android.webkit.ValueCallback;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings; import android.webkit.WebSettings;
import android.webkit.WebView; import android.webkit.WebView;
import androidx.activity.result.ActivityResultCallback; import androidx.activity.result.ActivityResultCallback;
@ -75,7 +79,6 @@ import org.json.JSONException;
*/ */
public class Bridge { public class Bridge {
private static final String PREFS_NAME = "CapacitorSettings";
private static final String PERMISSION_PREFS_NAME = "PluginPermStates"; private static final String PERMISSION_PREFS_NAME = "PluginPermStates";
private static final String BUNDLE_LAST_PLUGIN_ID_KEY = "capacitorLastActivityPluginId"; private static final String BUNDLE_LAST_PLUGIN_ID_KEY = "capacitorLastActivityPluginId";
private static final String BUNDLE_LAST_PLUGIN_CALL_METHOD_NAME_KEY = "capacitorLastActivityPluginMethod"; private static final String BUNDLE_LAST_PLUGIN_CALL_METHOD_NAME_KEY = "capacitorLastActivityPluginMethod";
@ -118,6 +121,8 @@ public class Bridge {
private HostMask appAllowNavigationMask; private HostMask appAllowNavigationMask;
private Set<String> allowedOriginRules = new HashSet<String>(); private Set<String> allowedOriginRules = new HashSet<String>();
private ArrayList<String> authorities = new ArrayList<>(); private ArrayList<String> authorities = new ArrayList<>();
private ArrayList<String> miscJSFileInjections = new ArrayList<String>();
private Boolean canInjectJS = true;
// A reference to the main WebView for the app // A reference to the main WebView for the app
private final WebView webView; private final WebView webView;
public final MockCordovaInterfaceImpl cordovaInterface; public final MockCordovaInterfaceImpl cordovaInterface;
@ -275,9 +280,23 @@ public class Bridge {
webView.setWebChromeClient(new BridgeWebChromeClient(this)); webView.setWebChromeClient(new BridgeWebChromeClient(this));
webView.setWebViewClient(this.webViewClient); webView.setWebViewClient(this.webViewClient);
if (Build.VERSION.SDK_INT >= 24 && config.isResolveServiceWorkerRequests()) {
ServiceWorkerController swController = ServiceWorkerController.getInstance();
swController.setServiceWorkerClient(
new ServiceWorkerClient() {
@Override
public WebResourceResponse shouldInterceptRequest(WebResourceRequest request) {
return getLocalServer().shouldInterceptRequest(request);
}
}
);
}
if (!isDeployDisabled() && !isNewBinary()) { if (!isDeployDisabled() && !isNewBinary()) {
SharedPreferences prefs = getContext() SharedPreferences prefs = getContext().getSharedPreferences(
.getSharedPreferences(com.getcapacitor.plugin.WebView.WEBVIEW_PREFS_NAME, Activity.MODE_PRIVATE); com.getcapacitor.plugin.WebView.WEBVIEW_PREFS_NAME,
Activity.MODE_PRIVATE
);
String path = prefs.getString(com.getcapacitor.plugin.WebView.CAP_SERVER_PATH, null); String path = prefs.getString(com.getcapacitor.plugin.WebView.CAP_SERVER_PATH, null);
if (path != null && !path.isEmpty() && new File(path).exists()) { if (path != null && !path.isEmpty() && new File(path).exists()) {
setServerBasePath(path); setServerBasePath(path);
@ -408,8 +427,10 @@ public class Bridge {
private boolean isNewBinary() { private boolean isNewBinary() {
String versionCode = ""; String versionCode = "";
String versionName = ""; String versionName = "";
SharedPreferences prefs = getContext() SharedPreferences prefs = getContext().getSharedPreferences(
.getSharedPreferences(com.getcapacitor.plugin.WebView.WEBVIEW_PREFS_NAME, Activity.MODE_PRIVATE); com.getcapacitor.plugin.WebView.WEBVIEW_PREFS_NAME,
Activity.MODE_PRIVATE
);
String lastVersionCode = prefs.getString(LAST_BINARY_VERSION_CODE, null); String lastVersionCode = prefs.getString(LAST_BINARY_VERSION_CODE, null);
String lastVersionName = prefs.getString(LAST_BINARY_VERSION_NAME, null); String lastVersionName = prefs.getString(LAST_BINARY_VERSION_NAME, null);
@ -552,6 +573,9 @@ public class Bridge {
public void reset() { public void reset() {
savedCalls = new HashMap<>(); savedCalls = new HashMap<>();
for (PluginHandle handle : this.plugins.values()) {
handle.getInstance().removeAllListeners();
}
} }
/** /**
@ -563,7 +587,6 @@ public class Bridge {
settings.setJavaScriptEnabled(true); settings.setJavaScriptEnabled(true);
settings.setDomStorageEnabled(true); settings.setDomStorageEnabled(true);
settings.setGeolocationEnabled(true); settings.setGeolocationEnabled(true);
settings.setDatabaseEnabled(true);
settings.setMediaPlaybackRequiresUserGesture(false); settings.setMediaPlaybackRequiresUserGesture(false);
settings.setJavaScriptCanOpenWindowsAutomatically(true); settings.setJavaScriptCanOpenWindowsAutomatically(true);
if (this.config.isMixedContentAllowed()) { if (this.config.isMixedContentAllowed()) {
@ -859,11 +882,11 @@ public class Bridge {
} }
public void triggerJSEvent(final String eventName, final String target) { public void triggerJSEvent(final String eventName, final String target) {
eval("window.Capacitor.triggerEvent(\"" + eventName + "\", \"" + target + "\")", s -> {}); eval("window.Capacitor.triggerEvent(\"" + eventName + "\", \"" + target + "\")", (s) -> {});
} }
public void triggerJSEvent(final String eventName, final String target, final String data) { public void triggerJSEvent(final String eventName, final String target, final String data) {
eval("window.Capacitor.triggerEvent(\"" + eventName + "\", \"" + target + "\", " + data + ")", s -> {}); eval("window.Capacitor.triggerEvent(\"" + eventName + "\", \"" + target + "\", " + data + ")", (s) -> {});
} }
public void triggerWindowJSEvent(final String eventName) { public void triggerWindowJSEvent(final String eventName) {
@ -1003,14 +1026,28 @@ public class Bridge {
String cordovaPluginsJS = JSExport.getCordovaPluginJS(context); String cordovaPluginsJS = JSExport.getCordovaPluginJS(context);
String cordovaPluginsFileJS = JSExport.getCordovaPluginsFileJS(context); String cordovaPluginsFileJS = JSExport.getCordovaPluginsFileJS(context);
String localUrlJS = "window.WEBVIEW_SERVER_URL = '" + localUrl + "';"; String localUrlJS = "window.WEBVIEW_SERVER_URL = '" + localUrl + "';";
String miscJS = JSExport.getMiscFileJS(miscJSFileInjections, context);
return new JSInjector(globalJS, bridgeJS, pluginJS, cordovaJS, cordovaPluginsJS, cordovaPluginsFileJS, localUrlJS); miscJSFileInjections = new ArrayList<>();
canInjectJS = false;
return new JSInjector(globalJS, bridgeJS, pluginJS, cordovaJS, cordovaPluginsJS, cordovaPluginsFileJS, localUrlJS, miscJS);
} catch (Exception ex) { } catch (Exception ex) {
Logger.error("Unable to export Capacitor JS. App will not function!", ex); Logger.error("Unable to export Capacitor JS. App will not function!", ex);
} }
return null; return null;
} }
/**
* Inject JavaScript from an external file before the WebView loads.
* @param path relative to public folder
*/
public void injectScriptBeforeLoad(String path) {
if (canInjectJS) {
miscJSFileInjections.add(path);
}
}
/** /**
* Restore any saved bundle state data * Restore any saved bundle state data
* @param savedInstanceState * @param savedInstanceState
@ -1026,8 +1063,13 @@ public class Bridge {
try { try {
JSObject options = new JSObject(lastOptionsJson); JSObject options = new JSObject(lastOptionsJson);
pluginCallForLastActivity = pluginCallForLastActivity = new PluginCall(
new PluginCall(msgHandler, lastPluginId, PluginCall.CALLBACK_ID_DANGLING, lastPluginCallMethod, options); msgHandler,
lastPluginId,
PluginCall.CALLBACK_ID_DANGLING,
lastPluginCallMethod,
options
);
} catch (JSONException ex) { } catch (JSONException ex) {
Logger.error("Unable to restore plugin call, unable to parse persisted JSON object", ex); Logger.error("Unable to restore plugin call, unable to parse persisted JSON object", ex);
} }
@ -1570,9 +1612,9 @@ public class Bridge {
config config
); );
if (webView instanceof CapacitorWebView) { if (webView instanceof CapacitorWebView capacitorWebView) {
CapacitorWebView capacitorWebView = (CapacitorWebView) webView;
capacitorWebView.setBridge(bridge); capacitorWebView.setBridge(bridge);
capacitorWebView.edgeToEdgeHandler(bridge);
} }
bridge.setCordovaWebView(mockWebView); bridge.setCordovaWebView(mockWebView);

View file

@ -25,7 +25,7 @@ public class BridgeActivity extends AppCompatActivity {
getApplication().setTheme(R.style.AppTheme_NoActionBar); getApplication().setTheme(R.style.AppTheme_NoActionBar);
setTheme(R.style.AppTheme_NoActionBar); setTheme(R.style.AppTheme_NoActionBar);
try { try {
setContentView(R.layout.bridge_layout_main); setContentView(R.layout.capacitor_bridge_layout_main);
} catch (Exception ex) { } catch (Exception ex) {
setContentView(R.layout.no_webview); setContentView(R.layout.no_webview);
return; return;

View file

@ -1,134 +0,0 @@
package com.getcapacitor;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import com.getcapacitor.android.R;
import java.util.ArrayList;
import java.util.List;
/**
* A simple {@link Fragment} subclass.
* Use the {@link BridgeFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class BridgeFragment extends Fragment {
private static final String ARG_START_DIR = "startDir";
protected Bridge bridge;
protected boolean keepRunning = true;
private final List<Class<? extends Plugin>> initialPlugins = new ArrayList<>();
private CapConfig config = null;
private final List<WebViewListener> webViewListeners = new ArrayList<>();
public BridgeFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param startDir the directory to serve content from
* @return A new instance of fragment BridgeFragment.
*/
public static BridgeFragment newInstance(String startDir) {
BridgeFragment fragment = new BridgeFragment();
Bundle args = new Bundle();
args.putString(ARG_START_DIR, startDir);
fragment.setArguments(args);
return fragment;
}
public void addPlugin(Class<? extends Plugin> plugin) {
this.initialPlugins.add(plugin);
}
public void setConfig(CapConfig config) {
this.config = config;
}
public Bridge getBridge() {
return bridge;
}
public void addWebViewListener(WebViewListener webViewListener) {
webViewListeners.add(webViewListener);
}
/**
* Load the WebView and create the Bridge
*/
protected void load(Bundle savedInstanceState) {
Logger.debug("Loading Bridge with BridgeFragment");
Bundle args = getArguments();
String startDir = null;
if (args != null) {
startDir = getArguments().getString(ARG_START_DIR);
}
bridge =
new Bridge.Builder(this)
.setInstanceState(savedInstanceState)
.setPlugins(initialPlugins)
.setConfig(config)
.addWebViewListeners(webViewListeners)
.create();
if (startDir != null) {
bridge.setServerAssetPath(startDir);
}
this.keepRunning = bridge.shouldKeepRunning();
}
@Override
public void onInflate(Context context, AttributeSet attrs, Bundle savedInstanceState) {
super.onInflate(context, attrs, savedInstanceState);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.bridge_fragment);
CharSequence c = a.getString(R.styleable.bridge_fragment_start_dir);
if (c != null) {
String startDir = c.toString();
Bundle args = new Bundle();
args.putString(ARG_START_DIR, startDir);
setArguments(args);
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_bridge, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
this.load(savedInstanceState);
}
@Override
public void onDestroy() {
super.onDestroy();
if (this.bridge != null) {
this.bridge.onDestroy();
}
}
}

View file

@ -67,15 +67,11 @@ public class BridgeWebChromeClient extends WebChromeClient {
}; };
permissionLauncher = bridge.registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), permissionCallback); permissionLauncher = bridge.registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), permissionCallback);
activityLauncher = activityLauncher = bridge.registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), (result) -> {
bridge.registerForActivityResult( if (activityListener != null) {
new ActivityResultContracts.StartActivityForResult(), activityListener.onActivityResult(result);
result -> { }
if (activityListener != null) { });
activityListener.onActivityResult(result);
}
}
);
} }
/** /**
@ -104,8 +100,6 @@ public class BridgeWebChromeClient extends WebChromeClient {
@Override @Override
public void onPermissionRequest(final PermissionRequest request) { public void onPermissionRequest(final PermissionRequest request) {
boolean isRequestPermissionRequired = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M;
List<String> permissionList = new ArrayList<>(); List<String> permissionList = new ArrayList<>();
if (Arrays.asList(request.getResources()).contains("android.webkit.resource.VIDEO_CAPTURE")) { if (Arrays.asList(request.getResources()).contains("android.webkit.resource.VIDEO_CAPTURE")) {
permissionList.add(Manifest.permission.CAMERA); permissionList.add(Manifest.permission.CAMERA);
@ -114,16 +108,15 @@ public class BridgeWebChromeClient extends WebChromeClient {
permissionList.add(Manifest.permission.MODIFY_AUDIO_SETTINGS); permissionList.add(Manifest.permission.MODIFY_AUDIO_SETTINGS);
permissionList.add(Manifest.permission.RECORD_AUDIO); permissionList.add(Manifest.permission.RECORD_AUDIO);
} }
if (!permissionList.isEmpty() && isRequestPermissionRequired) { if (!permissionList.isEmpty()) {
String[] permissions = permissionList.toArray(new String[0]); String[] permissions = permissionList.toArray(new String[0]);
permissionListener = permissionListener = (isGranted) -> {
isGranted -> { if (isGranted) {
if (isGranted) { request.grant(request.getResources());
request.grant(request.getResources()); } else {
} else { request.deny();
request.deny(); }
} };
};
permissionLauncher.launch(permissions); permissionLauncher.launch(permissions);
} else { } else {
request.grant(request.getResources()); request.grant(request.getResources());
@ -147,19 +140,14 @@ public class BridgeWebChromeClient extends WebChromeClient {
AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext()); AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext());
builder builder
.setMessage(message) .setMessage(message)
.setPositiveButton( .setPositiveButton("OK", (dialog, buttonIndex) -> {
"OK", dialog.dismiss();
(dialog, buttonIndex) -> { result.confirm();
dialog.dismiss(); })
result.confirm(); .setOnCancelListener((dialog) -> {
} dialog.dismiss();
) result.cancel();
.setOnCancelListener( });
dialog -> {
dialog.dismiss();
result.cancel();
}
);
AlertDialog dialog = builder.create(); AlertDialog dialog = builder.create();
@ -186,26 +174,18 @@ public class BridgeWebChromeClient extends WebChromeClient {
builder builder
.setMessage(message) .setMessage(message)
.setPositiveButton( .setPositiveButton("OK", (dialog, buttonIndex) -> {
"OK", dialog.dismiss();
(dialog, buttonIndex) -> { result.confirm();
dialog.dismiss(); })
result.confirm(); .setNegativeButton("Cancel", (dialog, buttonIndex) -> {
} dialog.dismiss();
) result.cancel();
.setNegativeButton( })
"Cancel", .setOnCancelListener((dialog) -> {
(dialog, buttonIndex) -> { dialog.dismiss();
dialog.dismiss(); result.cancel();
result.cancel(); });
}
)
.setOnCancelListener(
dialog -> {
dialog.dismiss();
result.cancel();
}
);
AlertDialog dialog = builder.create(); AlertDialog dialog = builder.create();
@ -235,28 +215,20 @@ public class BridgeWebChromeClient extends WebChromeClient {
builder builder
.setMessage(message) .setMessage(message)
.setView(input) .setView(input)
.setPositiveButton( .setPositiveButton("OK", (dialog, buttonIndex) -> {
"OK", dialog.dismiss();
(dialog, buttonIndex) -> {
dialog.dismiss();
String inputText1 = input.getText().toString().trim(); String inputText1 = input.getText().toString().trim();
result.confirm(inputText1); result.confirm(inputText1);
} })
) .setNegativeButton("Cancel", (dialog, buttonIndex) -> {
.setNegativeButton( dialog.dismiss();
"Cancel", result.cancel();
(dialog, buttonIndex) -> { })
dialog.dismiss(); .setOnCancelListener((dialog) -> {
result.cancel(); dialog.dismiss();
} result.cancel();
) });
.setOnCancelListener(
dialog -> {
dialog.dismiss();
result.cancel();
}
);
AlertDialog dialog = builder.create(); AlertDialog dialog = builder.create();
@ -277,22 +249,21 @@ public class BridgeWebChromeClient extends WebChromeClient {
final String[] geoPermissions = { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION }; final String[] geoPermissions = { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION };
if (!PermissionHelper.hasPermissions(bridge.getContext(), geoPermissions)) { if (!PermissionHelper.hasPermissions(bridge.getContext(), geoPermissions)) {
permissionListener = permissionListener = (isGranted) -> {
isGranted -> { if (isGranted) {
if (isGranted) { callback.invoke(origin, true, false);
} else {
final String[] coarsePermission = { Manifest.permission.ACCESS_COARSE_LOCATION };
if (
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
PermissionHelper.hasPermissions(bridge.getContext(), coarsePermission)
) {
callback.invoke(origin, true, false); callback.invoke(origin, true, false);
} else { } else {
final String[] coarsePermission = { Manifest.permission.ACCESS_COARSE_LOCATION }; callback.invoke(origin, false, false);
if (
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
PermissionHelper.hasPermissions(bridge.getContext(), coarsePermission)
) {
callback.invoke(origin, true, false);
} else {
callback.invoke(origin, false, false);
}
} }
}; }
};
permissionLauncher.launch(geoPermissions); permissionLauncher.launch(geoPermissions);
} else { } else {
// permission is already granted // permission is already granted
@ -315,15 +286,14 @@ public class BridgeWebChromeClient extends WebChromeClient {
if (isMediaCaptureSupported()) { if (isMediaCaptureSupported()) {
showMediaCaptureOrFilePicker(filePathCallback, fileChooserParams, captureVideo); showMediaCaptureOrFilePicker(filePathCallback, fileChooserParams, captureVideo);
} else { } else {
permissionListener = permissionListener = (isGranted) -> {
isGranted -> { if (isGranted) {
if (isGranted) { showMediaCaptureOrFilePicker(filePathCallback, fileChooserParams, captureVideo);
showMediaCaptureOrFilePicker(filePathCallback, fileChooserParams, captureVideo); } else {
} else { Logger.warn(Logger.tags("FileChooser"), "Camera permission not granted");
Logger.warn(Logger.tags("FileChooser"), "Camera permission not granted"); filePathCallback.onReceiveValue(null);
filePathCallback.onReceiveValue(null); }
} };
};
final String[] camPermission = { Manifest.permission.CAMERA }; final String[] camPermission = { Manifest.permission.CAMERA };
permissionLauncher.launch(camPermission); permissionLauncher.launch(camPermission);
} }
@ -375,14 +345,13 @@ public class BridgeWebChromeClient extends WebChromeClient {
return false; return false;
} }
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageFileUri); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageFileUri);
activityListener = activityListener = (activityResult) -> {
activityResult -> { Uri[] result = null;
Uri[] result = null; if (activityResult.getResultCode() == Activity.RESULT_OK) {
if (activityResult.getResultCode() == Activity.RESULT_OK) { result = new Uri[] { imageFileUri };
result = new Uri[] { imageFileUri }; }
} filePathCallback.onReceiveValue(result);
filePathCallback.onReceiveValue(result); };
};
activityLauncher.launch(takePictureIntent); activityLauncher.launch(takePictureIntent);
return true; return true;
@ -395,14 +364,13 @@ public class BridgeWebChromeClient extends WebChromeClient {
return false; return false;
} }
activityListener = activityListener = (activityResult) -> {
activityResult -> { Uri[] result = null;
Uri[] result = null; if (activityResult.getResultCode() == Activity.RESULT_OK) {
if (activityResult.getResultCode() == Activity.RESULT_OK) { result = new Uri[] { activityResult.getData().getData() };
result = new Uri[] { activityResult.getData().getData() }; }
} filePathCallback.onReceiveValue(result);
filePathCallback.onReceiveValue(result); };
};
activityLauncher.launch(takeVideoIntent); activityLauncher.launch(takeVideoIntent);
return true; return true;
@ -421,21 +389,20 @@ public class BridgeWebChromeClient extends WebChromeClient {
} }
} }
try { try {
activityListener = activityListener = (activityResult) -> {
activityResult -> { Uri[] result;
Uri[] result; Intent resultIntent = activityResult.getData();
Intent resultIntent = activityResult.getData(); if (activityResult.getResultCode() == Activity.RESULT_OK && resultIntent.getClipData() != null) {
if (activityResult.getResultCode() == Activity.RESULT_OK && resultIntent.getClipData() != null) { final int numFiles = resultIntent.getClipData().getItemCount();
final int numFiles = resultIntent.getClipData().getItemCount(); result = new Uri[numFiles];
result = new Uri[numFiles]; for (int i = 0; i < numFiles; i++) {
for (int i = 0; i < numFiles; i++) { result[i] = resultIntent.getClipData().getItemAt(i).getUri();
result[i] = resultIntent.getClipData().getItemAt(i).getUri();
}
} else {
result = WebChromeClient.FileChooserParams.parseResult(activityResult.getResultCode(), resultIntent);
} }
filePathCallback.onReceiveValue(result); } else {
}; result = WebChromeClient.FileChooserParams.parseResult(activityResult.getResultCode(), resultIntent);
}
filePathCallback.onReceiveValue(result);
};
activityLauncher.launch(intent); activityLauncher.launch(intent);
} catch (ActivityNotFoundException e) { } catch (ActivityNotFoundException e) {
filePathCallback.onReceiveValue(null); filePathCallback.onReceiveValue(null);

View file

@ -53,6 +53,8 @@ public class CapConfig {
private int minHuaweiWebViewVersion = DEFAULT_HUAWEI_WEBVIEW_VERSION; private int minHuaweiWebViewVersion = DEFAULT_HUAWEI_WEBVIEW_VERSION;
private String errorPath; private String errorPath;
private boolean zoomableWebView = false; private boolean zoomableWebView = false;
private boolean resolveServiceWorkerRequests = true;
private String adjustMarginsForEdgeToEdge = "disable";
// Embedded // Embedded
private String startPath; private String startPath;
@ -179,6 +181,8 @@ public class CapConfig {
this.minHuaweiWebViewVersion = builder.minHuaweiWebViewVersion; this.minHuaweiWebViewVersion = builder.minHuaweiWebViewVersion;
this.errorPath = builder.errorPath; this.errorPath = builder.errorPath;
this.zoomableWebView = builder.zoomableWebView; this.zoomableWebView = builder.zoomableWebView;
this.resolveServiceWorkerRequests = builder.resolveServiceWorkerRequests;
this.adjustMarginsForEdgeToEdge = builder.adjustMarginsForEdgeToEdge;
// Embedded // Embedded
this.startPath = builder.startPath; this.startPath = builder.startPath;
@ -247,6 +251,7 @@ public class CapConfig {
serverUrl = JSONUtils.getString(configJSON, "server.url", null); serverUrl = JSONUtils.getString(configJSON, "server.url", null);
hostname = JSONUtils.getString(configJSON, "server.hostname", hostname); hostname = JSONUtils.getString(configJSON, "server.hostname", hostname);
errorPath = JSONUtils.getString(configJSON, "server.errorPath", null); errorPath = JSONUtils.getString(configJSON, "server.errorPath", null);
startPath = JSONUtils.getString(configJSON, "server.appStartPath", null);
String configSchema = JSONUtils.getString(configJSON, "server.androidScheme", androidScheme); String configSchema = JSONUtils.getString(configJSON, "server.androidScheme", androidScheme);
if (this.validateScheme(configSchema)) { if (this.validateScheme(configSchema)) {
@ -256,24 +261,34 @@ public class CapConfig {
allowNavigation = JSONUtils.getArray(configJSON, "server.allowNavigation", null); allowNavigation = JSONUtils.getArray(configJSON, "server.allowNavigation", null);
// Android // Android
overriddenUserAgentString = overriddenUserAgentString = JSONUtils.getString(
JSONUtils.getString(configJSON, "android.overrideUserAgent", JSONUtils.getString(configJSON, "overrideUserAgent", null)); configJSON,
appendedUserAgentString = "android.overrideUserAgent",
JSONUtils.getString(configJSON, "android.appendUserAgent", JSONUtils.getString(configJSON, "appendUserAgent", null)); JSONUtils.getString(configJSON, "overrideUserAgent", null)
backgroundColor = );
JSONUtils.getString(configJSON, "android.backgroundColor", JSONUtils.getString(configJSON, "backgroundColor", null)); appendedUserAgentString = JSONUtils.getString(
allowMixedContent = configJSON,
JSONUtils.getBoolean( "android.appendUserAgent",
configJSON, JSONUtils.getString(configJSON, "appendUserAgent", null)
"android.allowMixedContent", );
JSONUtils.getBoolean(configJSON, "allowMixedContent", allowMixedContent) backgroundColor = JSONUtils.getString(
); configJSON,
"android.backgroundColor",
JSONUtils.getString(configJSON, "backgroundColor", null)
);
allowMixedContent = JSONUtils.getBoolean(
configJSON,
"android.allowMixedContent",
JSONUtils.getBoolean(configJSON, "allowMixedContent", allowMixedContent)
);
minWebViewVersion = JSONUtils.getInt(configJSON, "android.minWebViewVersion", DEFAULT_ANDROID_WEBVIEW_VERSION); minWebViewVersion = JSONUtils.getInt(configJSON, "android.minWebViewVersion", DEFAULT_ANDROID_WEBVIEW_VERSION);
minHuaweiWebViewVersion = JSONUtils.getInt(configJSON, "android.minHuaweiWebViewVersion", DEFAULT_HUAWEI_WEBVIEW_VERSION); minHuaweiWebViewVersion = JSONUtils.getInt(configJSON, "android.minHuaweiWebViewVersion", DEFAULT_HUAWEI_WEBVIEW_VERSION);
captureInput = JSONUtils.getBoolean(configJSON, "android.captureInput", captureInput); captureInput = JSONUtils.getBoolean(configJSON, "android.captureInput", captureInput);
useLegacyBridge = JSONUtils.getBoolean(configJSON, "android.useLegacyBridge", useLegacyBridge); useLegacyBridge = JSONUtils.getBoolean(configJSON, "android.useLegacyBridge", useLegacyBridge);
webContentsDebuggingEnabled = JSONUtils.getBoolean(configJSON, "android.webContentsDebuggingEnabled", isDebug); webContentsDebuggingEnabled = JSONUtils.getBoolean(configJSON, "android.webContentsDebuggingEnabled", isDebug);
zoomableWebView = JSONUtils.getBoolean(configJSON, "android.zoomEnabled", JSONUtils.getBoolean(configJSON, "zoomEnabled", false)); zoomableWebView = JSONUtils.getBoolean(configJSON, "android.zoomEnabled", JSONUtils.getBoolean(configJSON, "zoomEnabled", false));
resolveServiceWorkerRequests = JSONUtils.getBoolean(configJSON, "android.resolveServiceWorkerRequests", true);
adjustMarginsForEdgeToEdge = JSONUtils.getString(configJSON, "android.adjustMarginsForEdgeToEdge", "disable");
String logBehavior = JSONUtils.getString( String logBehavior = JSONUtils.getString(
configJSON, configJSON,
@ -291,7 +306,11 @@ public class CapConfig {
loggingEnabled = isDebug; loggingEnabled = isDebug;
} }
initialFocus = JSONUtils.getBoolean(configJSON, "android.initialFocus", initialFocus); initialFocus = JSONUtils.getBoolean(
configJSON,
"android.initialFocus",
JSONUtils.getBoolean(configJSON, "initialFocus", initialFocus)
);
// Plugins // Plugins
pluginsConfiguration = deserializePluginsConfig(JSONUtils.getObject(configJSON, "plugins")); pluginsConfiguration = deserializePluginsConfig(JSONUtils.getObject(configJSON, "plugins"));
@ -362,6 +381,10 @@ public class CapConfig {
return captureInput; return captureInput;
} }
public boolean isResolveServiceWorkerRequests() {
return resolveServiceWorkerRequests;
}
public boolean isWebContentsDebuggingEnabled() { public boolean isWebContentsDebuggingEnabled() {
return webContentsDebuggingEnabled; return webContentsDebuggingEnabled;
} }
@ -382,6 +405,10 @@ public class CapConfig {
return useLegacyBridge; return useLegacyBridge;
} }
public String adjustMarginsForEdgeToEdge() {
return adjustMarginsForEdgeToEdge;
}
public int getMinWebViewVersion() { public int getMinWebViewVersion() {
if (minWebViewVersion < MINIMUM_ANDROID_WEBVIEW_VERSION) { if (minWebViewVersion < MINIMUM_ANDROID_WEBVIEW_VERSION) {
Logger.warn("Specified minimum webview version is too low, defaulting to " + MINIMUM_ANDROID_WEBVIEW_VERSION); Logger.warn("Specified minimum webview version is too low, defaulting to " + MINIMUM_ANDROID_WEBVIEW_VERSION);
@ -561,6 +588,8 @@ public class CapConfig {
private int minWebViewVersion = DEFAULT_ANDROID_WEBVIEW_VERSION; private int minWebViewVersion = DEFAULT_ANDROID_WEBVIEW_VERSION;
private int minHuaweiWebViewVersion = DEFAULT_HUAWEI_WEBVIEW_VERSION; private int minHuaweiWebViewVersion = DEFAULT_HUAWEI_WEBVIEW_VERSION;
private boolean zoomableWebView = false; private boolean zoomableWebView = false;
private boolean resolveServiceWorkerRequests = true;
private String adjustMarginsForEdgeToEdge = "disable";
// Embedded // Embedded
private String startPath = null; private String startPath = null;
@ -660,6 +689,11 @@ public class CapConfig {
return this; return this;
} }
public Builder setResolveServiceWorkerRequests(boolean resolveServiceWorkerRequests) {
this.resolveServiceWorkerRequests = resolveServiceWorkerRequests;
return this;
}
public Builder setWebContentsDebuggingEnabled(boolean webContentsDebuggingEnabled) { public Builder setWebContentsDebuggingEnabled(boolean webContentsDebuggingEnabled) {
this.webContentsDebuggingEnabled = webContentsDebuggingEnabled; this.webContentsDebuggingEnabled = webContentsDebuggingEnabled;
return this; return this;

View file

@ -1,12 +1,17 @@
package com.getcapacitor; package com.getcapacitor;
import android.content.Context; import android.content.Context;
import android.os.Build;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.inputmethod.BaseInputConnection; import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputConnection;
import android.webkit.WebView; import android.webkit.WebView;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
public class CapacitorWebView extends WebView { public class CapacitorWebView extends WebView {
@ -49,4 +54,36 @@ public class CapacitorWebView extends WebView {
} }
return super.dispatchKeyEvent(event); return super.dispatchKeyEvent(event);
} }
public void edgeToEdgeHandler(Bridge bridge) {
String configEdgeToEdge = bridge.getConfig().adjustMarginsForEdgeToEdge();
if (configEdgeToEdge.equals("disable")) return;
boolean autoMargins = false;
boolean forceMargins = configEdgeToEdge.equals("force");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && configEdgeToEdge.equals("auto")) {
TypedValue value = new TypedValue();
boolean foundOptOut = getContext().getTheme().resolveAttribute(android.R.attr.windowOptOutEdgeToEdgeEnforcement, value, true);
boolean optOutValue = value.data != 0; // value is set to -1 on true as of Android 15, so we have to do this.
autoMargins = !(foundOptOut && optOutValue);
}
if (forceMargins || autoMargins) {
ViewCompat.setOnApplyWindowInsetsListener(this, (v, windowInsets) -> {
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams();
mlp.leftMargin = insets.left;
mlp.bottomMargin = insets.bottom;
mlp.rightMargin = insets.right;
mlp.topMargin = insets.top;
v.setLayoutParams(mlp);
// Don't pass window insets to children
return WindowInsetsCompat.CONSUMED;
});
}
}
} }

View file

@ -219,7 +219,8 @@ public class FileUtils {
int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
cursor.moveToFirst(); cursor.moveToFirst();
String name = (cursor.getString(nameIndex)); String name = (cursor.getString(nameIndex));
File file = new File(context.getFilesDir(), name); String fileName = sanitizeFilename(name);
File file = new File(context.getFilesDir(), fileName);
try { try {
InputStream inputStream = context.getContentResolver().openInputStream(uri); InputStream inputStream = context.getContentResolver().openInputStream(uri);
FileOutputStream outputStream = new FileOutputStream(file); FileOutputStream outputStream = new FileOutputStream(file);
@ -289,4 +290,14 @@ public class FileUtils {
} }
return null; return null;
} }
private static String sanitizeFilename(String displayName) {
String[] badCharacters = new String[] { "..", "/" };
String[] segments = displayName.split("/");
String fileName = segments[segments.length - 1];
for (String suspString : badCharacters) {
fileName = fileName.replace(suspString, "_");
}
return fileName;
}
} }

View file

@ -21,6 +21,21 @@ public class JSExport {
return "window.Capacitor = { DEBUG: " + isDebug + ", isLoggingEnabled: " + loggingEnabled + ", Plugins: {} };"; return "window.Capacitor = { DEBUG: " + isDebug + ", isLoggingEnabled: " + loggingEnabled + ", Plugins: {} };";
} }
public static String getMiscFileJS(ArrayList<String> paths, Context context) {
List<String> lines = new ArrayList<>();
for (String path : paths) {
try {
String fileContent = readFileFromAssets(context.getAssets(), "public/" + path);
lines.add(fileContent);
} catch (IOException ex) {
Logger.error("Unable to read public/" + path);
}
}
return TextUtils.join("\n", lines);
}
public static String getCordovaJS(Context context) { public static String getCordovaJS(Context context) {
String fileContent = ""; String fileContent = "";
try { try {

View file

@ -20,6 +20,7 @@ class JSInjector {
private String cordovaPluginsJS; private String cordovaPluginsJS;
private String cordovaPluginsFileJS; private String cordovaPluginsFileJS;
private String localUrlJS; private String localUrlJS;
private String miscJS;
public JSInjector( public JSInjector(
String globalJS, String globalJS,
@ -29,6 +30,19 @@ class JSInjector {
String cordovaPluginsJS, String cordovaPluginsJS,
String cordovaPluginsFileJS, String cordovaPluginsFileJS,
String localUrlJS String localUrlJS
) {
this(globalJS, bridgeJS, pluginJS, cordovaJS, cordovaPluginsJS, cordovaPluginsFileJS, localUrlJS, null);
}
public JSInjector(
String globalJS,
String bridgeJS,
String pluginJS,
String cordovaJS,
String cordovaPluginsJS,
String cordovaPluginsFileJS,
String localUrlJS,
String miscJS
) { ) {
this.globalJS = globalJS; this.globalJS = globalJS;
this.bridgeJS = bridgeJS; this.bridgeJS = bridgeJS;
@ -37,6 +51,7 @@ class JSInjector {
this.cordovaPluginsJS = cordovaPluginsJS; this.cordovaPluginsJS = cordovaPluginsJS;
this.cordovaPluginsFileJS = cordovaPluginsFileJS; this.cordovaPluginsFileJS = cordovaPluginsFileJS;
this.localUrlJS = localUrlJS; this.localUrlJS = localUrlJS;
this.miscJS = miscJS;
} }
/** /**
@ -45,7 +60,7 @@ class JSInjector {
* @return * @return
*/ */
public String getScriptString() { public String getScriptString() {
return ( String scriptString =
globalJS + globalJS +
"\n\n" + "\n\n" +
localUrlJS + localUrlJS +
@ -58,8 +73,13 @@ class JSInjector {
"\n\n" + "\n\n" +
cordovaPluginsFileJS + cordovaPluginsFileJS +
"\n\n" + "\n\n" +
cordovaPluginsJS cordovaPluginsJS;
);
if (miscJS != null) {
scriptString += "\n\n" + miscJS;
}
return scriptString;
} }
/** /**

View file

@ -150,10 +150,8 @@ public class MessageHandler {
} }
private void callCordovaPluginMethod(String callbackId, String service, String action, String actionArgs) { private void callCordovaPluginMethod(String callbackId, String service, String action, String actionArgs) {
bridge.execute( bridge.execute(() -> {
() -> { cordovaPluginManager.exec(service, action, callbackId, actionArgs);
cordovaPluginManager.exec(service, action, callbackId, actionArgs); });
}
);
} }
} }

View file

@ -114,7 +114,7 @@ public class Plugin {
// register callbacks annotated with ActivityCallback for activity results // register callbacks annotated with ActivityCallback for activity results
ActivityResultLauncher<Intent> launcher = bridge.registerForActivityResult( ActivityResultLauncher<Intent> launcher = bridge.registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(), new ActivityResultContracts.StartActivityForResult(),
result -> triggerActivityCallback(method, result) (result) -> triggerActivityCallback(method, result)
); );
activityLaunchers.put(method.getName(), launcher); activityLaunchers.put(method.getName(), launcher);
@ -122,7 +122,7 @@ public class Plugin {
// register callbacks annotated with PermissionCallback for permission results // register callbacks annotated with PermissionCallback for permission results
ActivityResultLauncher<String[]> launcher = bridge.registerForActivityResult( ActivityResultLauncher<String[]> launcher = bridge.registerForActivityResult(
new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultContracts.RequestMultiplePermissions(),
permissions -> triggerPermissionCallback(method, permissions) (permissions) -> triggerPermissionCallback(method, permissions)
); );
permissionLaunchers.put(method.getName(), launcher); permissionLaunchers.put(method.getName(), launcher);
@ -762,6 +762,10 @@ public class Plugin {
call.resolve(); call.resolve();
} }
public void removeAllListeners() {
eventListeners.clear();
}
/** /**
* Exported plugin call for checking the granted status for each permission * Exported plugin call for checking the granted status for each permission
* declared on the plugin. This plugin call responds with a mapping of permissions to * declared on the plugin. This plugin call responds with a mapping of permissions to

View file

@ -50,25 +50,6 @@ public class PluginCall {
this.msgHandler.sendResponseMessage(this, successResult, null); this.msgHandler.sendResponseMessage(this, successResult, null);
} }
/**
* @deprecated
* Use {@link #resolve(JSObject data)}
*/
@Deprecated
public void success(JSObject data) {
PluginResult result = new PluginResult(data);
this.msgHandler.sendResponseMessage(this, result, null);
}
/**
* @deprecated
* Use {@link #resolve()}
*/
@Deprecated
public void success() {
this.resolve(new JSObject());
}
public void resolve(JSObject data) { public void resolve(JSObject data) {
PluginResult result = new PluginResult(data); PluginResult result = new PluginResult(data);
this.msgHandler.sendResponseMessage(this, result, null); this.msgHandler.sendResponseMessage(this, result, null);
@ -90,33 +71,6 @@ public class PluginCall {
this.msgHandler.sendResponseMessage(this, null, errorResult); this.msgHandler.sendResponseMessage(this, null, errorResult);
} }
/**
* @deprecated
* Use {@link #reject(String msg, Exception ex)}
*/
@Deprecated
public void error(String msg, Exception ex) {
reject(msg, ex);
}
/**
* @deprecated
* Use {@link #reject(String msg, String code, Exception ex)}
*/
@Deprecated
public void error(String msg, String code, Exception ex) {
reject(msg, code, ex);
}
/**
* @deprecated
* Use {@link #reject(String msg)}
*/
@Deprecated
public void error(String msg) {
reject(msg);
}
public void reject(String msg, String code, Exception ex, JSObject data) { public void reject(String msg, String code, Exception ex, JSObject data) {
PluginResult errorResult = new PluginResult(); PluginResult errorResult = new PluginResult();

View file

@ -77,7 +77,9 @@ public class UriMatcher {
UriMatcher node = this; UriMatcher node = this;
for (int i = -2; i < numTokens; i++) { for (int i = -2; i < numTokens; i++) {
String token; String token;
if (i == -2) token = scheme; else if (i == -1) token = authority; else token = tokens[i]; if (i == -2) token = scheme;
else if (i == -1) token = authority;
else token = tokens[i];
ArrayList<UriMatcher> children = node.mChildren; ArrayList<UriMatcher> children = node.mChildren;
int numChildren = children.size(); int numChildren = children.size();
UriMatcher child; UriMatcher child;
@ -130,7 +132,9 @@ public class UriMatcher {
for (int i = -2; i < li; i++) { for (int i = -2; i < li; i++) {
String u; String u;
if (i == -2) u = uri.getScheme(); else if (i == -1) u = uri.getAuthority(); else u = pathSegments.get(i); if (i == -2) u = uri.getScheme();
else if (i == -1) u = uri.getAuthority();
else u = pathSegments.get(i);
ArrayList<UriMatcher> list = node.mChildren; ArrayList<UriMatcher> list = node.mChildren;
if (list == null) { if (list == null) {
break; break;
@ -139,7 +143,7 @@ public class UriMatcher {
int lj = list.size(); int lj = list.size();
for (int j = 0; j < lj; j++) { for (int j = 0; j < lj; j++) {
UriMatcher n = list.get(j); UriMatcher n = list.get(j);
which_switch:switch (n.mWhich) { which_switch: switch (n.mWhich) {
case MASK: case MASK:
if (HostMask.Parser.parse(n.mText).matches(u)) { if (HostMask.Parser.parse(n.mText).matches(u)) {
node = n; node = n;

View file

@ -260,6 +260,15 @@ public class WebViewLocalServer {
headers.put(header.getKey(), header.getValue()); headers.put(header.getKey(), header.getValue());
} }
// a workaround for the following android web view issue:
// https://issues.chromium.org/issues/40450316
// x-cap-user-agent contains the user agent set in JavaScript
String userAgentValue = headers.getString("x-cap-user-agent");
if (userAgentValue != null) {
headers.put("User-Agent", userAgentValue);
}
headers.remove("x-cap-user-agent");
HttpRequestHandler.HttpURLConnectionBuilder connectionBuilder = new HttpRequestHandler.HttpURLConnectionBuilder() HttpRequestHandler.HttpURLConnectionBuilder connectionBuilder = new HttpRequestHandler.HttpURLConnectionBuilder()
.setUrl(url) .setUrl(url)
.setMethod(request.getMethod()) .setMethod(request.getMethod())

View file

@ -7,5 +7,4 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
public @interface ActivityCallback { public @interface ActivityCallback {}
}

View file

@ -7,5 +7,4 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
public @interface PermissionCallback { public @interface PermissionCallback {}
}

View file

@ -72,14 +72,12 @@ public class MockCordovaWebViewImpl implements CordovaWebView {
public void onNativeToJsMessageAvailable(final NativeToJsMessageQueue queue) { public void onNativeToJsMessageAvailable(final NativeToJsMessageQueue queue) {
cordova cordova
.getActivity() .getActivity()
.runOnUiThread( .runOnUiThread(() -> {
() -> { String js = queue.popAndEncodeAsJs();
String js = queue.popAndEncodeAsJs(); if (js != null) {
if (js != null) { webView.evaluateJavascript(js, null);
webView.evaluateJavascript(js, null);
}
} }
); });
} }
} }
@ -194,7 +192,7 @@ public class MockCordovaWebViewImpl implements CordovaWebView {
} }
public void triggerDocumentEvent(final String eventName) { public void triggerDocumentEvent(final String eventName) {
eval("window.Capacitor.triggerEvent('" + eventName + "', 'document');", s -> {}); eval("window.Capacitor.triggerEvent('" + eventName + "', 'document');", (s) -> {});
} }
@Override @Override

View file

@ -46,34 +46,31 @@ public class CapacitorCookies extends Plugin {
@PluginMethod @PluginMethod
public void getCookies(PluginCall call) { public void getCookies(PluginCall call) {
this.bridge.eval( this.bridge.eval("document.cookie", (value) -> {
"document.cookie", String cookies = value.substring(1, value.length() - 1);
value -> { String[] cookieArray = cookies.split(";");
String cookies = value.substring(1, value.length() - 1);
String[] cookieArray = cookies.split(";");
JSObject cookieMap = new JSObject(); JSObject cookieMap = new JSObject();
for (String cookie : cookieArray) { for (String cookie : cookieArray) {
if (cookie.length() > 0) { if (cookie.length() > 0) {
String[] keyValue = cookie.split("=", 2); String[] keyValue = cookie.split("=", 2);
if (keyValue.length == 2) { if (keyValue.length == 2) {
String key = keyValue[0].trim(); String key = keyValue[0].trim();
String val = keyValue[1].trim(); String val = keyValue[1].trim();
try { try {
key = URLDecoder.decode(keyValue[0].trim(), StandardCharsets.UTF_8.name()); key = URLDecoder.decode(keyValue[0].trim(), StandardCharsets.UTF_8.name());
val = URLDecoder.decode(keyValue[1].trim(), StandardCharsets.UTF_8.name()); val = URLDecoder.decode(keyValue[1].trim(), StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException ignored) {} } catch (UnsupportedEncodingException ignored) {}
cookieMap.put(key, val); cookieMap.put(key, val);
}
} }
} }
call.resolve(cookieMap);
} }
);
call.resolve(cookieMap);
});
} }
@PluginMethod @PluginMethod

View file

@ -398,6 +398,19 @@ public class HttpRequestHandler {
boolean isHttpMutate = method.equals("DELETE") || method.equals("PATCH") || method.equals("POST") || method.equals("PUT"); boolean isHttpMutate = method.equals("DELETE") || method.equals("PATCH") || method.equals("POST") || method.equals("PUT");
// a workaround for the following android web view issue:
// https://issues.chromium.org/issues/40450316
// x-cap-user-agent contains the user agent set in JavaScript
String userAgentValue = headers.getString("x-cap-user-agent");
if (userAgentValue != null) {
headers.put("User-Agent", userAgentValue);
}
headers.remove("x-cap-user-agent");
if (!headers.has("User-Agent") && !headers.has("user-agent")) {
headers.put("User-Agent", bridge.getConfig().getOverriddenUserAgentString());
}
URL url = new URL(urlString); URL url = new URL(urlString);
HttpURLConnectionBuilder connectionBuilder = new HttpURLConnectionBuilder() HttpURLConnectionBuilder connectionBuilder = new HttpURLConnectionBuilder()
.setUrl(url) .setUrl(url)

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.getcapacitor.BridgeActivity"
>
<com.getcapacitor.CapacitorWebView
android:id="@+id/webview"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -1,13 +0,0 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F0FF1414"
tools:context="com.getcapacitor.BridgeFragment">
<com.getcapacitor.CapacitorWebView
android:id="@+id/webview"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</FrameLayout>

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="bridge_fragment">
<attr name="start_dir" format="string"/>
</declare-styleable>
</resources>

View file

@ -1,6 +1,6 @@
{ {
"name": "@capacitor/android", "name": "@capacitor/android",
"version": "6.1.2", "version": "7.4.1",
"description": "Capacitor: Cross-platform apps with JavaScript and the web", "description": "Capacitor: Cross-platform apps with JavaScript and the web",
"homepage": "https://capacitorjs.com", "homepage": "https://capacitorjs.com",
"author": "Ionic Team <hi@ionic.io> (https://ionic.io)", "author": "Ionic Team <hi@ionic.io> (https://ionic.io)",
@ -23,7 +23,7 @@
"verify": "./gradlew clean lint build test -b capacitor/build.gradle" "verify": "./gradlew clean lint build test -b capacitor/build.gradle"
}, },
"peerDependencies": { "peerDependencies": {
"@capacitor/core": "^6.1.0" "@capacitor/core": "^7.4.0"
}, },
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"

View file

@ -1,15 +1,84 @@
# Capacitor CLI # Capacitor CLI
The Capacitor command-line interface should be installed locally and executed through `npm` scripts. The Capacitor command-line interface (CLI) is a tool for creating and managing Capacitor applications. While it can be installed globally, it's recommended to install it locally in your project and execute through `npm` scripts.
``` ## Installation
### Project Installation (Recommended)
Install the CLI locally in your project:
```bash
npm install @capacitor/cli --save-dev npm install @capacitor/cli --save-dev
``` ```
### Global Installation
While not recommended for project use, you can install the CLI globally:
```bash
npm install -g @capacitor/cli
```
## Using Capacitor CLI ## Using Capacitor CLI
Consult the Getting Started guide for information on using the CLI and Capacitor scripts. The CLI can be used through the `capacitor` or `cap` command. When installed locally, use it through your project's `npm` scripts or `npx`.
Common commands:
- `cap init`: Initialize a new Capacitor project
- `cap add`: Add a native platform (ios, android)
- `cap sync`: Sync your web code to your native projects
For detailed information, consult the [Getting Started guide](https://capacitorjs.com/docs/getting-started).
## Local Development
If you're contributing to the Capacitor CLI or testing local changes:
1. Clone and setup:
```bash
git clone https://github.com/ionic-team/capacitor.git
cd cli
npm install
```
2. Build the CLI:
```bash
npm run build
```
3. Create a local link:
```bash
npm link
```
4. Development workflow:
- Run `npm run watch` to automatically rebuild on changes
- Use `capacitor` or `cap` commands to test your changes
- Run `npm test` to execute the test suite
## Debugging
### Using VS Code Launch Configurations
The CLI includes VS Code launch configurations for debugging. To debug a CLI command:
1. Open the project in VS Code
2. Right now we don't have debugging working in the ts files, so select one of the .js files inside of /dist/\*\*.js
3. Place a breakpoint
4. Press F5 or go to Run > Start Debugging
5. Select a launch config and run filling out the path you want to run the cli in, and the command that you want run.
You can add more configurations by copying and modifying the existing ones in `.vscode/launch.json`.
## Contributing
Contributions are welcome! Please read our [Contributing Guide](https://github.com/ionic-team/capacitor/blob/main/CONTRIBUTING.md) for details.
### License ### License
* [MIT](https://github.com/ionic-team/capacitor/blob/HEAD/LICENSE) - [MIT](https://github.com/ionic-team/capacitor/blob/HEAD/LICENSE)

View file

@ -2,7 +2,7 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.createLocalProperties = exports.addAndroid = void 0; exports.createLocalProperties = exports.addAndroid = void 0;
const tslib_1 = require("tslib"); const tslib_1 = require("tslib");
const utils_fs_1 = require("@ionic/utils-fs"); const fs_extra_1 = require("fs-extra");
const os_1 = require("os"); const os_1 = require("os");
const path_1 = require("path"); const path_1 = require("path");
const colors_1 = tslib_1.__importDefault(require("../colors")); const colors_1 = tslib_1.__importDefault(require("../colors"));
@ -17,7 +17,7 @@ async function addAndroid(config) {
exports.addAndroid = addAndroid; exports.addAndroid = addAndroid;
async function createLocalProperties(platformDir) { async function createLocalProperties(platformDir) {
const defaultAndroidPath = (0, path_1.join)((0, os_1.homedir)(), 'Library/Android/sdk'); const defaultAndroidPath = (0, path_1.join)((0, os_1.homedir)(), 'Library/Android/sdk');
if (await (0, utils_fs_1.pathExists)(defaultAndroidPath)) { if (await (0, fs_extra_1.pathExists)(defaultAndroidPath)) {
const localSettings = ` const localSettings = `
## This file is automatically generated by Android Studio. ## This file is automatically generated by Android Studio.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED! # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
@ -30,7 +30,7 @@ async function createLocalProperties(platformDir) {
# header note. # header note.
sdk.dir=${defaultAndroidPath} sdk.dir=${defaultAndroidPath}
`; `;
await (0, utils_fs_1.writeFile)((0, path_1.join)(platformDir, 'local.properties'), localSettings, { await (0, fs_extra_1.writeFile)((0, path_1.join)(platformDir, 'local.properties'), localSettings, {
encoding: 'utf-8', encoding: 'utf-8',
}); });
// Only sync if we were able to create the local properties above, otherwise // Only sync if we were able to create the local properties above, otherwise

View file

@ -12,9 +12,7 @@ async function buildAndroid(config, buildOptions) {
const releaseType = (_a = buildOptions.androidreleasetype) !== null && _a !== void 0 ? _a : 'AAB'; const releaseType = (_a = buildOptions.androidreleasetype) !== null && _a !== void 0 ? _a : 'AAB';
const releaseTypeIsAAB = releaseType === 'AAB'; const releaseTypeIsAAB = releaseType === 'AAB';
const flavor = (_b = buildOptions.flavor) !== null && _b !== void 0 ? _b : ''; const flavor = (_b = buildOptions.flavor) !== null && _b !== void 0 ? _b : '';
const arg = releaseTypeIsAAB const arg = releaseTypeIsAAB ? `:app:bundle${flavor}Release` : `assemble${flavor}Release`;
? `:app:bundle${flavor}Release`
: `assemble${flavor}Release`;
const gradleArgs = [arg]; const gradleArgs = [arg];
try { try {
await (0, common_1.runTask)('Running Gradle build', async () => (0, subprocess_1.runCommand)('./gradlew', gradleArgs, { await (0, common_1.runTask)('Running Gradle build', async () => (0, subprocess_1.runCommand)('./gradlew', gradleArgs, {

View file

@ -1,7 +1,7 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.editProjectSettingsAndroid = exports.resolvePlugin = exports.getAndroidPlugins = exports.checkAndroidPackage = void 0; exports.editProjectSettingsAndroid = exports.resolvePlugin = exports.getAndroidPlugins = exports.checkAndroidPackage = void 0;
const utils_fs_1 = require("@ionic/utils-fs"); const fs_extra_1 = require("fs-extra");
const path_1 = require("path"); const path_1 = require("path");
const common_1 = require("../common"); const common_1 = require("../common");
const cordova_1 = require("../cordova"); const cordova_1 = require("../cordova");
@ -20,12 +20,10 @@ async function resolvePlugin(plugin) {
var _a; var _a;
const platform = 'android'; const platform = 'android';
if ((_a = plugin.manifest) === null || _a === void 0 ? void 0 : _a.android) { if ((_a = plugin.manifest) === null || _a === void 0 ? void 0 : _a.android) {
let pluginFilesPath = plugin.manifest.android.src let pluginFilesPath = plugin.manifest.android.src ? plugin.manifest.android.src : platform;
? plugin.manifest.android.src
: platform;
const absolutePath = (0, path_1.join)(plugin.rootPath, pluginFilesPath, plugin.id); const absolutePath = (0, path_1.join)(plugin.rootPath, pluginFilesPath, plugin.id);
// Android folder shouldn't have subfolders, but they used to, so search for them for compatibility reasons // Android folder shouldn't have subfolders, but they used to, so search for them for compatibility reasons
if (await (0, utils_fs_1.pathExists)(absolutePath)) { if (await (0, fs_extra_1.pathExists)(absolutePath)) {
pluginFilesPath = (0, path_1.join)(platform, plugin.id); pluginFilesPath = (0, path_1.join)(platform, plugin.id);
} }
plugin.android = { plugin.android = {
@ -38,8 +36,7 @@ async function resolvePlugin(plugin) {
type: 1 /* PluginType.Cordova */, type: 1 /* PluginType.Cordova */,
path: 'src/' + platform, path: 'src/' + platform,
}; };
if ((0, cordova_1.getIncompatibleCordovaPlugins)(platform).includes(plugin.id) || if ((0, cordova_1.getIncompatibleCordovaPlugins)(platform).includes(plugin.id) || !(0, plugin_1.getPluginPlatform)(plugin, platform)) {
!(0, plugin_1.getPluginPlatform)(plugin, platform)) {
plugin.android.type = 2 /* PluginType.Incompatible */; plugin.android.type = 2 /* PluginType.Incompatible */;
} }
} }
@ -65,33 +62,33 @@ async function editProjectSettingsAndroid(config) {
const domainPath = appId.split('.').join('/'); const domainPath = appId.split('.').join('/');
// Make the package source path to the new plugin Java file // Make the package source path to the new plugin Java file
const newJavaPath = (0, path_1.resolve)(config.android.srcMainDirAbs, `java/${domainPath}`); const newJavaPath = (0, path_1.resolve)(config.android.srcMainDirAbs, `java/${domainPath}`);
if (!(await (0, utils_fs_1.pathExists)(newJavaPath))) { if (!(await (0, fs_extra_1.pathExists)(newJavaPath))) {
await (0, utils_fs_1.mkdirp)(newJavaPath); await (0, fs_extra_1.mkdirp)(newJavaPath);
} }
await (0, utils_fs_1.copy)((0, path_1.resolve)(config.android.srcMainDirAbs, 'java/com/getcapacitor/myapp/MainActivity.java'), (0, path_1.resolve)(newJavaPath, 'MainActivity.java')); await (0, fs_extra_1.copy)((0, path_1.resolve)(config.android.srcMainDirAbs, 'java/com/getcapacitor/myapp/MainActivity.java'), (0, path_1.resolve)(newJavaPath, 'MainActivity.java'));
if (appId.split('.')[1] !== 'getcapacitor') { if (appId.split('.')[1] !== 'getcapacitor') {
await (0, utils_fs_1.remove)((0, path_1.resolve)(config.android.srcMainDirAbs, 'java/com/getcapacitor')); await (0, fs_extra_1.remove)((0, path_1.resolve)(config.android.srcMainDirAbs, 'java/com/getcapacitor'));
} }
// Remove our template 'com' folder if their ID doesn't have it // Remove our template 'com' folder if their ID doesn't have it
if (appId.split('.')[0] !== 'com') { if (appId.split('.')[0] !== 'com') {
await (0, utils_fs_1.remove)((0, path_1.resolve)(config.android.srcMainDirAbs, 'java/com/')); await (0, fs_extra_1.remove)((0, path_1.resolve)(config.android.srcMainDirAbs, 'java/com/'));
} }
// Update the package in the MainActivity java file // Update the package in the MainActivity java file
const activityPath = (0, path_1.resolve)(newJavaPath, 'MainActivity.java'); const activityPath = (0, path_1.resolve)(newJavaPath, 'MainActivity.java');
let activityContent = await (0, utils_fs_1.readFile)(activityPath, { encoding: 'utf-8' }); let activityContent = await (0, fs_extra_1.readFile)(activityPath, { encoding: 'utf-8' });
activityContent = activityContent.replace(/package ([^;]*)/, `package ${appId}`); activityContent = activityContent.replace(/package ([^;]*)/, `package ${appId}`);
await (0, utils_fs_1.writeFile)(activityPath, activityContent, { encoding: 'utf-8' }); await (0, fs_extra_1.writeFile)(activityPath, activityContent, { encoding: 'utf-8' });
// Update the applicationId in build.gradle // Update the applicationId in build.gradle
let gradleContent = await (0, utils_fs_1.readFile)(buildGradlePath, { encoding: 'utf-8' }); let gradleContent = await (0, fs_extra_1.readFile)(buildGradlePath, { encoding: 'utf-8' });
gradleContent = gradleContent.replace(/applicationId "[^"]+"/, `applicationId "${appId}"`); gradleContent = gradleContent.replace(/applicationId "[^"]+"/, `applicationId "${appId}"`);
// Update the namespace in build.gradle // Update the namespace in build.gradle
gradleContent = gradleContent.replace(/namespace "[^"]+"/, `namespace "${appId}"`); gradleContent = gradleContent.replace(/namespace "[^"]+"/, `namespace "${appId}"`);
await (0, utils_fs_1.writeFile)(buildGradlePath, gradleContent, { encoding: 'utf-8' }); await (0, fs_extra_1.writeFile)(buildGradlePath, gradleContent, { encoding: 'utf-8' });
// Update the settings in res/values/strings.xml // Update the settings in res/values/strings.xml
const stringsPath = (0, path_1.resolve)(config.android.resDirAbs, 'values/strings.xml'); const stringsPath = (0, path_1.resolve)(config.android.resDirAbs, 'values/strings.xml');
let stringsContent = await (0, utils_fs_1.readFile)(stringsPath, { encoding: 'utf-8' }); let stringsContent = await (0, fs_extra_1.readFile)(stringsPath, { encoding: 'utf-8' });
stringsContent = stringsContent.replace(/com.getcapacitor.myapp/g, appId); stringsContent = stringsContent.replace(/com.getcapacitor.myapp/g, appId);
stringsContent = stringsContent.replace(/My App/g, appName); stringsContent = stringsContent.replace(/My App/g, appName);
await (0, utils_fs_1.writeFile)(stringsPath, stringsContent); await (0, fs_extra_1.writeFile)(stringsPath, stringsContent);
} }
exports.editProjectSettingsAndroid = editProjectSettingsAndroid; exports.editProjectSettingsAndroid = editProjectSettingsAndroid;

View file

@ -2,21 +2,18 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.doctorAndroid = void 0; exports.doctorAndroid = void 0;
const tslib_1 = require("tslib"); const tslib_1 = require("tslib");
const utils_fs_1 = require("@ionic/utils-fs"); const fs_extra_1 = require("fs-extra");
const path_1 = require("path"); const path_1 = require("path");
const colors_1 = tslib_1.__importDefault(require("../colors")); const colors_1 = tslib_1.__importDefault(require("../colors"));
const common_1 = require("../common"); const common_1 = require("../common");
const errors_1 = require("../errors"); const errors_1 = require("../errors");
const log_1 = require("../log"); const log_1 = require("../log");
const fs_1 = require("../util/fs");
const xml_1 = require("../util/xml"); const xml_1 = require("../util/xml");
async function doctorAndroid(config) { async function doctorAndroid(config) {
var _a; var _a;
try { try {
await (0, common_1.check)([ await (0, common_1.check)([checkAndroidInstalled, () => checkGradlew(config), () => checkAppSrcDirs(config)]);
checkAndroidInstalled,
() => checkGradlew(config),
() => checkAppSrcDirs(config),
]);
(0, log_1.logSuccess)('Android looking great! 👌'); (0, log_1.logSuccess)('Android looking great! 👌');
} }
catch (e) { catch (e) {
@ -28,20 +25,20 @@ async function doctorAndroid(config) {
} }
exports.doctorAndroid = doctorAndroid; exports.doctorAndroid = doctorAndroid;
async function checkAppSrcDirs(config) { async function checkAppSrcDirs(config) {
if (!(await (0, utils_fs_1.pathExists)(config.android.appDirAbs))) { if (!(await (0, fs_extra_1.pathExists)(config.android.appDirAbs))) {
return `${colors_1.default.strong(config.android.appDir)} directory is missing in ${colors_1.default.strong(config.android.platformDir)}`; return `${colors_1.default.strong(config.android.appDir)} directory is missing in ${colors_1.default.strong(config.android.platformDir)}`;
} }
if (!(await (0, utils_fs_1.pathExists)(config.android.srcMainDirAbs))) { if (!(await (0, fs_extra_1.pathExists)(config.android.srcMainDirAbs))) {
return `${colors_1.default.strong(config.android.srcMainDir)} directory is missing in ${colors_1.default.strong(config.android.platformDir)}`; return `${colors_1.default.strong(config.android.srcMainDir)} directory is missing in ${colors_1.default.strong(config.android.platformDir)}`;
} }
if (!(await (0, utils_fs_1.pathExists)(config.android.assetsDirAbs))) { if (!(await (0, fs_extra_1.pathExists)(config.android.assetsDirAbs))) {
return `${colors_1.default.strong(config.android.assetsDir)} directory is missing in ${colors_1.default.strong(config.android.platformDir)}`; return `${colors_1.default.strong(config.android.assetsDir)} directory is missing in ${colors_1.default.strong(config.android.platformDir)}`;
} }
if (!(await (0, utils_fs_1.pathExists)(config.android.webDirAbs))) { if (!(await (0, fs_extra_1.pathExists)(config.android.webDirAbs))) {
return `${colors_1.default.strong(config.android.webDir)} directory is missing in ${colors_1.default.strong(config.android.platformDir)}`; return `${colors_1.default.strong(config.android.webDir)} directory is missing in ${colors_1.default.strong(config.android.platformDir)}`;
} }
const appSrcMainAssetsWwwIndexHtmlDir = (0, path_1.join)(config.android.webDirAbs, 'index.html'); const appSrcMainAssetsWwwIndexHtmlDir = (0, path_1.join)(config.android.webDirAbs, 'index.html');
if (!(await (0, utils_fs_1.pathExists)(appSrcMainAssetsWwwIndexHtmlDir))) { if (!(await (0, fs_extra_1.pathExists)(appSrcMainAssetsWwwIndexHtmlDir))) {
return `${colors_1.default.strong('index.html')} file is missing in ${colors_1.default.strong(config.android.webDirAbs)}`; return `${colors_1.default.strong('index.html')} file is missing in ${colors_1.default.strong(config.android.webDirAbs)}`;
} }
return checkAndroidManifestFile(config); return checkAndroidManifestFile(config);
@ -49,7 +46,7 @@ async function checkAppSrcDirs(config) {
async function checkAndroidManifestFile(config) { async function checkAndroidManifestFile(config) {
const manifestFileName = 'AndroidManifest.xml'; const manifestFileName = 'AndroidManifest.xml';
const manifestFilePath = (0, path_1.join)(config.android.srcMainDirAbs, manifestFileName); const manifestFilePath = (0, path_1.join)(config.android.srcMainDirAbs, manifestFileName);
if (!(await (0, utils_fs_1.pathExists)(manifestFilePath))) { if (!(await (0, fs_extra_1.pathExists)(manifestFilePath))) {
return `${colors_1.default.strong(manifestFileName)} is missing in ${colors_1.default.strong(config.android.srcMainDir)}`; return `${colors_1.default.strong(manifestFileName)} is missing in ${colors_1.default.strong(config.android.srcMainDir)}`;
} }
try { try {
@ -70,22 +67,22 @@ async function checkAndroidManifestData(config, xmlData) {
return `Missing ${colors_1.default.input('<application>')} XML node as a child node of ${colors_1.default.input('<manifest>')} in ${colors_1.default.strong(config.android.srcMainDir)}`; return `Missing ${colors_1.default.input('<application>')} XML node as a child node of ${colors_1.default.input('<manifest>')} in ${colors_1.default.strong(config.android.srcMainDir)}`;
} }
let mainActivityClassPath = ''; let mainActivityClassPath = '';
const mainApplicationNode = applicationChildNodes.find(applicationChildNode => { const mainApplicationNode = applicationChildNodes.find((applicationChildNode) => {
const activityChildNodes = applicationChildNode.activity; const activityChildNodes = applicationChildNode.activity;
if (!Array.isArray(activityChildNodes)) { if (!Array.isArray(activityChildNodes)) {
return false; return false;
} }
const mainActivityNode = activityChildNodes.find(activityChildNode => { const mainActivityNode = activityChildNodes.find((activityChildNode) => {
const intentFilterChildNodes = activityChildNode['intent-filter']; const intentFilterChildNodes = activityChildNode['intent-filter'];
if (!Array.isArray(intentFilterChildNodes)) { if (!Array.isArray(intentFilterChildNodes)) {
return false; return false;
} }
return intentFilterChildNodes.find(intentFilterChildNode => { return intentFilterChildNodes.find((intentFilterChildNode) => {
const actionChildNodes = intentFilterChildNode.action; const actionChildNodes = intentFilterChildNode.action;
if (!Array.isArray(actionChildNodes)) { if (!Array.isArray(actionChildNodes)) {
return false; return false;
} }
const mainActionChildNode = actionChildNodes.find(actionChildNode => { const mainActionChildNode = actionChildNodes.find((actionChildNode) => {
const androidName = actionChildNode.$['android:name']; const androidName = actionChildNode.$['android:name'];
return androidName === 'android.intent.action.MAIN'; return androidName === 'android.intent.action.MAIN';
}); });
@ -96,7 +93,7 @@ async function checkAndroidManifestData(config, xmlData) {
if (!Array.isArray(categoryChildNodes)) { if (!Array.isArray(categoryChildNodes)) {
return false; return false;
} }
return categoryChildNodes.find(categoryChildNode => { return categoryChildNodes.find((categoryChildNode) => {
const androidName = categoryChildNode.$['android:name']; const androidName = categoryChildNode.$['android:name'];
return androidName === 'android.intent.category.LAUNCHER'; return androidName === 'android.intent.category.LAUNCHER';
}); });
@ -117,12 +114,12 @@ async function checkAndroidManifestData(config, xmlData) {
} }
async function checkPackage(config, mainActivityClassPath) { async function checkPackage(config, mainActivityClassPath) {
const appSrcMainJavaDir = (0, path_1.join)(config.android.srcMainDirAbs, 'java'); const appSrcMainJavaDir = (0, path_1.join)(config.android.srcMainDirAbs, 'java');
if (!(await (0, utils_fs_1.pathExists)(appSrcMainJavaDir))) { if (!(await (0, fs_extra_1.pathExists)(appSrcMainJavaDir))) {
return `${colors_1.default.strong('java')} directory is missing in ${colors_1.default.strong(appSrcMainJavaDir)}`; return `${colors_1.default.strong('java')} directory is missing in ${colors_1.default.strong(appSrcMainJavaDir)}`;
} }
const mainActivityClassName = mainActivityClassPath.split('.').pop(); const mainActivityClassName = mainActivityClassPath.split('.').pop();
const srcFiles = await (0, utils_fs_1.readdirp)(appSrcMainJavaDir, { const srcFiles = await (0, fs_1.readdirp)(appSrcMainJavaDir, {
filter: entry => !entry.stats.isDirectory() && filter: (entry) => !entry.stats.isDirectory() &&
['.java', '.kt'].includes((0, path_1.extname)(entry.path)) && ['.java', '.kt'].includes((0, path_1.extname)(entry.path)) &&
mainActivityClassName === (0, path_1.parse)(entry.path).name, mainActivityClassName === (0, path_1.parse)(entry.path).name,
}); });
@ -134,10 +131,10 @@ async function checkPackage(config, mainActivityClassPath) {
async function checkBuildGradle(config) { async function checkBuildGradle(config) {
const fileName = 'build.gradle'; const fileName = 'build.gradle';
const filePath = (0, path_1.join)(config.android.appDirAbs, fileName); const filePath = (0, path_1.join)(config.android.appDirAbs, fileName);
if (!(await (0, utils_fs_1.pathExists)(filePath))) { if (!(await (0, fs_extra_1.pathExists)(filePath))) {
return `${colors_1.default.strong(fileName)} file is missing in ${colors_1.default.strong(config.android.appDir)}`; return `${colors_1.default.strong(fileName)} file is missing in ${colors_1.default.strong(config.android.appDir)}`;
} }
let fileContent = await (0, utils_fs_1.readFile)(filePath, { encoding: 'utf-8' }); let fileContent = await (0, fs_extra_1.readFile)(filePath, { encoding: 'utf-8' });
fileContent = fileContent.replace(/'|"/g, '').replace(/\s+/g, ' '); fileContent = fileContent.replace(/'|"/g, '').replace(/\s+/g, ' ');
const searchFor = `applicationId`; const searchFor = `applicationId`;
if (fileContent.indexOf(searchFor) === -1) { if (fileContent.indexOf(searchFor) === -1) {
@ -148,7 +145,7 @@ async function checkBuildGradle(config) {
async function checkGradlew(config) { async function checkGradlew(config) {
const fileName = 'gradlew'; const fileName = 'gradlew';
const filePath = (0, path_1.join)(config.android.platformDirAbs, fileName); const filePath = (0, path_1.join)(config.android.platformDirAbs, fileName);
if (!(await (0, utils_fs_1.pathExists)(filePath))) { if (!(await (0, fs_extra_1.pathExists)(filePath))) {
return `${colors_1.default.strong(fileName)} file is missing in ${colors_1.default.strong(config.android.platformDir)}`; return `${colors_1.default.strong(fileName)} file is missing in ${colors_1.default.strong(config.android.platformDir)}`;
} }
return null; return null;

View file

@ -2,8 +2,8 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.openAndroid = void 0; exports.openAndroid = void 0;
const tslib_1 = require("tslib"); const tslib_1 = require("tslib");
const utils_fs_1 = require("@ionic/utils-fs");
const debug_1 = tslib_1.__importDefault(require("debug")); const debug_1 = tslib_1.__importDefault(require("debug"));
const fs_extra_1 = require("fs-extra");
const open_1 = tslib_1.__importDefault(require("open")); const open_1 = tslib_1.__importDefault(require("open"));
const colors_1 = tslib_1.__importDefault(require("../colors")); const colors_1 = tslib_1.__importDefault(require("../colors"));
const log_1 = require("../log"); const log_1 = require("../log");
@ -12,7 +12,7 @@ async function openAndroid(config) {
const androidStudioPath = await config.android.studioPath; const androidStudioPath = await config.android.studioPath;
const dir = config.android.platformDirAbs; const dir = config.android.platformDirAbs;
try { try {
if (!(await (0, utils_fs_1.pathExists)(androidStudioPath))) { if (!(await (0, fs_extra_1.pathExists)(androidStudioPath))) {
throw new Error(`Android Studio does not exist at: ${androidStudioPath}`); throw new Error(`Android Studio does not exist at: ${androidStudioPath}`);
} }
await (0, open_1.default)(dir, { app: { name: androidStudioPath }, wait: false }); await (0, open_1.default)(dir, { app: { name: androidStudioPath }, wait: false });

View file

@ -9,7 +9,7 @@ const common_1 = require("../common");
const native_run_1 = require("../util/native-run"); const native_run_1 = require("../util/native-run");
const subprocess_1 = require("../util/subprocess"); const subprocess_1 = require("../util/subprocess");
const debug = (0, debug_1.default)('capacitor:android:run'); const debug = (0, debug_1.default)('capacitor:android:run');
async function runAndroid(config, { target: selectedTarget, flavor: selectedFlavor, forwardPorts: selectedPorts, }) { async function runAndroid(config, { target: selectedTarget, flavor: selectedFlavor, forwardPorts: selectedPorts }) {
var _a; var _a;
const target = await (0, common_1.promptForPlatformTarget)(await (0, native_run_1.getPlatformTargets)('android'), selectedTarget); const target = await (0, common_1.promptForPlatformTarget)(await (0, native_run_1.getPlatformTargets)('android'), selectedTarget);
const runFlavor = selectedFlavor || ((_a = config.android) === null || _a === void 0 ? void 0 : _a.flavor) || ''; const runFlavor = selectedFlavor || ((_a = config.android) === null || _a === void 0 ? void 0 : _a.flavor) || '';

View file

@ -2,8 +2,8 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.handleCordovaPluginsGradle = exports.installGradlePlugins = exports.updateAndroid = void 0; exports.handleCordovaPluginsGradle = exports.installGradlePlugins = exports.updateAndroid = void 0;
const tslib_1 = require("tslib"); const tslib_1 = require("tslib");
const utils_fs_1 = require("@ionic/utils-fs");
const debug_1 = tslib_1.__importDefault(require("debug")); const debug_1 = tslib_1.__importDefault(require("debug"));
const fs_extra_1 = require("fs-extra");
const path_1 = require("path"); const path_1 = require("path");
const colors_1 = tslib_1.__importDefault(require("../colors")); const colors_1 = tslib_1.__importDefault(require("../colors"));
const common_1 = require("../common"); const common_1 = require("../common");
@ -19,25 +19,26 @@ const common_2 = require("./common");
const platform = 'android'; const platform = 'android';
const debug = (0, debug_1.default)('capacitor:android:update'); const debug = (0, debug_1.default)('capacitor:android:update');
async function updateAndroid(config) { async function updateAndroid(config) {
var _a;
const plugins = await getPluginsTask(config); const plugins = await getPluginsTask(config);
const capacitorPlugins = plugins.filter(p => (0, plugin_1.getPluginType)(p, platform) === 0 /* PluginType.Core */); const capacitorPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 0 /* PluginType.Core */);
(0, plugin_1.printPlugins)(capacitorPlugins, 'android'); (0, plugin_1.printPlugins)(capacitorPlugins, 'android');
await writePluginsJson(config, capacitorPlugins); await writePluginsJson(config, capacitorPlugins);
await removePluginsNativeFiles(config); await removePluginsNativeFiles(config);
const cordovaPlugins = plugins.filter(p => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */); const cordovaPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */);
await (0, migrate_1.patchOldCapacitorPlugins)(config); await (0, migrate_1.patchOldCapacitorPlugins)(config);
if (cordovaPlugins.length > 0) { if (cordovaPlugins.length > 0) {
await copyPluginsNativeFiles(config, cordovaPlugins); await copyPluginsNativeFiles(config, cordovaPlugins);
} }
if (!(await (0, utils_fs_1.pathExists)(config.android.webDirAbs))) { if (!(await (0, fs_extra_1.pathExists)(config.android.webDirAbs))) {
await (0, copy_1.copy)(config, platform); await (0, copy_1.copy)(config, platform);
} }
await (0, cordova_1.handleCordovaPluginsJS)(cordovaPlugins, config, platform); await (0, cordova_1.handleCordovaPluginsJS)(cordovaPlugins, config, platform);
await (0, cordova_1.checkPluginDependencies)(plugins, platform); await (0, cordova_1.checkPluginDependencies)(plugins, platform, (_a = config.app.extConfig.cordova) === null || _a === void 0 ? void 0 : _a.failOnUninstalledPlugins);
await installGradlePlugins(config, capacitorPlugins, cordovaPlugins); await installGradlePlugins(config, capacitorPlugins, cordovaPlugins);
await handleCordovaPluginsGradle(config, cordovaPlugins); await handleCordovaPluginsGradle(config, cordovaPlugins);
await (0, cordova_1.writeCordovaAndroidManifest)(cordovaPlugins, config, platform); await (0, cordova_1.writeCordovaAndroidManifest)(cordovaPlugins, config, platform);
const incompatibleCordovaPlugins = plugins.filter(p => (0, plugin_1.getPluginType)(p, platform) === 2 /* PluginType.Incompatible */); const incompatibleCordovaPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 2 /* PluginType.Incompatible */);
(0, plugin_1.printPlugins)(incompatibleCordovaPlugins, platform, 'incompatible'); (0, plugin_1.printPlugins)(incompatibleCordovaPlugins, platform, 'incompatible');
await (0, common_1.checkPlatformVersions)(config, platform); await (0, common_1.checkPlatformVersions)(config, platform);
} }
@ -48,7 +49,7 @@ function getGradlePackageName(id) {
async function writePluginsJson(config, plugins) { async function writePluginsJson(config, plugins) {
const classes = await findAndroidPluginClasses(plugins); const classes = await findAndroidPluginClasses(plugins);
const pluginsJsonPath = (0, path_1.resolve)(config.android.assetsDirAbs, 'capacitor.plugins.json'); const pluginsJsonPath = (0, path_1.resolve)(config.android.assetsDirAbs, 'capacitor.plugins.json');
await (0, utils_fs_1.writeJSON)(pluginsJsonPath, classes, { spaces: '\t' }); await (0, fs_extra_1.writeJSON)(pluginsJsonPath, classes, { spaces: '\t' });
} }
async function findAndroidPluginClasses(plugins) { async function findAndroidPluginClasses(plugins) {
const entries = []; const entries = [];
@ -62,15 +63,14 @@ async function findAndroidPluginClassesInPlugin(plugin) {
return []; return [];
} }
const srcPath = (0, path_1.resolve)(plugin.rootPath, plugin.android.path, 'src/main'); const srcPath = (0, path_1.resolve)(plugin.rootPath, plugin.android.path, 'src/main');
const srcFiles = await (0, utils_fs_1.readdirp)(srcPath, { const srcFiles = await (0, fs_1.readdirp)(srcPath, {
filter: entry => !entry.stats.isDirectory() && filter: (entry) => !entry.stats.isDirectory() && ['.java', '.kt'].includes((0, path_1.extname)(entry.path)),
['.java', '.kt'].includes((0, path_1.extname)(entry.path)),
}); });
const classRegex = /^@(?:CapacitorPlugin|NativePlugin)[\s\S]+?class ([\w]+)/gm; const classRegex = /^@(?:CapacitorPlugin|NativePlugin)[\s\S]+?class ([\w]+)/gm;
const packageRegex = /^package ([\w.]+);?$/gm; const packageRegex = /^package ([\w.]+);?$/gm;
debug('Searching %O source files in %O by %O regex', srcFiles.length, srcPath, classRegex); debug('Searching %O source files in %O by %O regex', srcFiles.length, srcPath, classRegex);
const entries = await Promise.all(srcFiles.map(async (srcFile) => { const entries = await Promise.all(srcFiles.map(async (srcFile) => {
const srcFileContents = await (0, utils_fs_1.readFile)(srcFile, { encoding: 'utf-8' }); const srcFileContents = await (0, fs_extra_1.readFile)(srcFile, { encoding: 'utf-8' });
classRegex.lastIndex = 0; classRegex.lastIndex = 0;
const classMatch = classRegex.exec(srcFileContents); const classMatch = classRegex.exec(srcFileContents);
if (classMatch) { if (classMatch) {
@ -79,8 +79,7 @@ async function findAndroidPluginClassesInPlugin(plugin) {
packageRegex.lastIndex = 0; packageRegex.lastIndex = 0;
const packageMatch = packageRegex.exec(srcFileContents.substring(0, classMatch.index)); const packageMatch = packageRegex.exec(srcFileContents.substring(0, classMatch.index));
if (!packageMatch) { if (!packageMatch) {
(0, errors_1.fatal)(`Package could not be parsed from Android plugin.\n` + (0, errors_1.fatal)(`Package could not be parsed from Android plugin.\n` + `Location: ${colors_1.default.strong(srcFile)}`);
`Location: ${colors_1.default.strong(srcFile)}`);
} }
const packageName = packageMatch[1]; const packageName = packageMatch[1];
const classpath = `${packageName}.${className}`; const classpath = `${packageName}.${className}`;
@ -107,7 +106,7 @@ async function installGradlePlugins(config, capacitorPlugins, cordovaPlugins) {
include ':capacitor-android' include ':capacitor-android'
project(':capacitor-android').projectDir = new File('${relativeCapcitorAndroidPath}') project(':capacitor-android').projectDir = new File('${relativeCapcitorAndroidPath}')
${capacitorPlugins ${capacitorPlugins
.map(p => { .map((p) => {
if (!p.android) { if (!p.android) {
return ''; return '';
} }
@ -121,7 +120,7 @@ project(':${getGradlePackageName(p.id)}').projectDir = new File('${relativePlugi
const applyArray = []; const applyArray = [];
const frameworksArray = []; const frameworksArray = [];
let prefsArray = []; let prefsArray = [];
cordovaPlugins.map(p => { cordovaPlugins.map((p) => {
const relativePluginPath = (0, fs_1.convertToUnixPath)((0, path_1.relative)(dependencyPath, p.rootPath)); const relativePluginPath = (0, fs_1.convertToUnixPath)((0, path_1.relative)(dependencyPath, p.rootPath));
const frameworks = (0, plugin_1.getPlatformElement)(p, platform, 'framework'); const frameworks = (0, plugin_1.getPlatformElement)(p, platform, 'framework');
frameworks.map((framework) => { frameworks.map((framework) => {
@ -148,15 +147,15 @@ project(':${getGradlePackageName(p.id)}').projectDir = new File('${relativePlugi
android { android {
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_17 sourceCompatibility JavaVersion.VERSION_21
targetCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_21
} }
} }
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle" apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
dependencies { dependencies {
${capacitorPlugins ${capacitorPlugins
.map(p => { .map((p) => {
return ` implementation project(':${getGradlePackageName(p.id)}')`; return ` implementation project(':${getGradlePackageName(p.id)}')`;
}) })
.join('\n')} .join('\n')}
@ -168,20 +167,20 @@ if (hasProperty('postBuildExtras')) {
postBuildExtras() postBuildExtras()
} }
`; `;
await (0, utils_fs_1.writeFile)((0, path_1.join)(settingsPath, 'capacitor.settings.gradle'), settingsLines); await (0, fs_extra_1.writeFile)((0, path_1.join)(settingsPath, 'capacitor.settings.gradle'), settingsLines);
await (0, utils_fs_1.writeFile)((0, path_1.join)(dependencyPath, 'capacitor.build.gradle'), dependencyLines); await (0, fs_extra_1.writeFile)((0, path_1.join)(dependencyPath, 'capacitor.build.gradle'), dependencyLines);
} }
exports.installGradlePlugins = installGradlePlugins; exports.installGradlePlugins = installGradlePlugins;
async function handleCordovaPluginsGradle(config, cordovaPlugins) { async function handleCordovaPluginsGradle(config, cordovaPlugins) {
var _a, _b, _c; var _a, _b, _c;
const pluginsGradlePath = (0, path_1.join)(config.android.cordovaPluginsDirAbs, 'build.gradle'); const pluginsGradlePath = (0, path_1.join)(config.android.cordovaPluginsDirAbs, 'build.gradle');
const kotlinNeeded = await kotlinNeededCheck(config, cordovaPlugins); const kotlinNeeded = await kotlinNeededCheck(config, cordovaPlugins);
const kotlinVersionString = (_c = (_b = (_a = config.app.extConfig.cordova) === null || _a === void 0 ? void 0 : _a.preferences) === null || _b === void 0 ? void 0 : _b.GradlePluginKotlinVersion) !== null && _c !== void 0 ? _c : '1.8.20'; const kotlinVersionString = (_c = (_b = (_a = config.app.extConfig.cordova) === null || _a === void 0 ? void 0 : _a.preferences) === null || _b === void 0 ? void 0 : _b.GradlePluginKotlinVersion) !== null && _c !== void 0 ? _c : '1.9.25';
const frameworksArray = []; const frameworksArray = [];
let prefsArray = []; let prefsArray = [];
const applyArray = []; const applyArray = [];
applyArray.push(`apply from: "cordova.variables.gradle"`); applyArray.push(`apply from: "cordova.variables.gradle"`);
cordovaPlugins.map(p => { cordovaPlugins.map((p) => {
const relativePluginPath = (0, fs_1.convertToUnixPath)((0, path_1.relative)(config.android.cordovaPluginsDirAbs, p.rootPath)); const relativePluginPath = (0, fs_1.convertToUnixPath)((0, path_1.relative)(config.android.cordovaPluginsDirAbs, p.rootPath));
const frameworks = (0, plugin_1.getPlatformElement)(p, platform, 'framework'); const frameworks = (0, plugin_1.getPlatformElement)(p, platform, 'framework');
frameworks.map((framework) => { frameworks.map((framework) => {
@ -198,7 +197,7 @@ async function handleCordovaPluginsGradle(config, cordovaPlugins) {
prefsArray = prefsArray.concat((0, plugin_1.getAllElements)(p, platform, 'preference')); prefsArray = prefsArray.concat((0, plugin_1.getAllElements)(p, platform, 'preference'));
}); });
let frameworkString = frameworksArray let frameworkString = frameworksArray
.map(f => { .map((f) => {
if (f.startsWith('platform(')) { if (f.startsWith('platform(')) {
return ` implementation ${f}`; return ` implementation ${f}`;
} }
@ -213,7 +212,7 @@ async function handleCordovaPluginsGradle(config, cordovaPlugins) {
frameworkString += `\n implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"`; frameworkString += `\n implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"`;
} }
const applyString = applyArray.join('\n'); const applyString = applyArray.join('\n');
let buildGradle = await (0, utils_fs_1.readFile)(pluginsGradlePath, { encoding: 'utf-8' }); let buildGradle = await (0, fs_extra_1.readFile)(pluginsGradlePath, { encoding: 'utf-8' });
buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + frameworkString.concat('\n') + ' $2'); buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + frameworkString.concat('\n') + ' $2');
buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + applyString.concat('\n') + '$2'); buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + applyString.concat('\n') + '$2');
if (kotlinNeeded) { if (kotlinNeeded) {
@ -223,7 +222,7 @@ async function handleCordovaPluginsGradle(config, cordovaPlugins) {
buildGradle = buildGradle.replace(/(apply\splugin:\s'com\.android\.library')/, `$1\napply plugin: 'kotlin-android'`); buildGradle = buildGradle.replace(/(apply\splugin:\s'com\.android\.library')/, `$1\napply plugin: 'kotlin-android'`);
buildGradle = buildGradle.replace(/(compileOptions\s{\n((\t{2}|\s{8}).+\n)+(\t|\s{4})})\n(})/, `$1\n sourceSets {\n main.java.srcDirs += 'src/main/kotlin'\n }\n$5`); buildGradle = buildGradle.replace(/(compileOptions\s{\n((\t{2}|\s{8}).+\n)+(\t|\s{4})})\n(})/, `$1\n sourceSets {\n main.java.srcDirs += 'src/main/kotlin'\n }\n$5`);
} }
await (0, utils_fs_1.writeFile)(pluginsGradlePath, buildGradle); await (0, fs_extra_1.writeFile)(pluginsGradlePath, buildGradle);
const cordovaVariables = `// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN const cordovaVariables = `// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
ext { ext {
cdvMinSdkVersion = project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : ${config.android.minVersion} cdvMinSdkVersion = project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : ${config.android.minVersion}
@ -231,13 +230,12 @@ ext {
cdvPluginPostBuildExtras = [] cdvPluginPostBuildExtras = []
cordovaConfig = [:] cordovaConfig = [:]
}`; }`;
await (0, utils_fs_1.writeFile)((0, path_1.join)(config.android.cordovaPluginsDirAbs, 'cordova.variables.gradle'), cordovaVariables); await (0, fs_extra_1.writeFile)((0, path_1.join)(config.android.cordovaPluginsDirAbs, 'cordova.variables.gradle'), cordovaVariables);
} }
exports.handleCordovaPluginsGradle = handleCordovaPluginsGradle; exports.handleCordovaPluginsGradle = handleCordovaPluginsGradle;
async function kotlinNeededCheck(config, cordovaPlugins) { async function kotlinNeededCheck(config, cordovaPlugins) {
var _a, _b; var _a, _b;
if (((_b = (_a = config.app.extConfig.cordova) === null || _a === void 0 ? void 0 : _a.preferences) === null || _b === void 0 ? void 0 : _b.GradlePluginKotlinEnabled) !== if (((_b = (_a = config.app.extConfig.cordova) === null || _a === void 0 ? void 0 : _a.preferences) === null || _b === void 0 ? void 0 : _b.GradlePluginKotlinEnabled) !== 'true') {
'true') {
for (const plugin of cordovaPlugins) { for (const plugin of cordovaPlugins) {
const androidPlatform = (0, plugin_1.getPluginPlatform)(plugin, platform); const androidPlatform = (0, plugin_1.getPluginPlatform)(plugin, platform);
const sourceFiles = androidPlatform['source-file']; const sourceFiles = androidPlatform['source-file'];
@ -268,10 +266,8 @@ async function copyPluginsNativeFiles(config, cordovaPlugins) {
if (fileName.split('.').pop() === 'aidl') { if (fileName.split('.').pop() === 'aidl') {
baseFolder = 'aidl/'; baseFolder = 'aidl/';
} }
const target = sourceFile.$['target-dir'] const target = sourceFile.$['target-dir'].replace('app/src/main/', '').replace('src/', baseFolder);
.replace('app/src/main/', '') await (0, fs_extra_1.copy)((0, plugin_1.getFilePath)(config, p, sourceFile.$.src), (0, path_1.join)(pluginsPath, target, fileName));
.replace('src/', baseFolder);
await (0, utils_fs_1.copy)((0, plugin_1.getFilePath)(config, p, sourceFile.$.src), (0, path_1.join)(pluginsPath, target, fileName));
} }
} }
const resourceFiles = androidPlatform['resource-file']; const resourceFiles = androidPlatform['resource-file'];
@ -279,22 +275,22 @@ async function copyPluginsNativeFiles(config, cordovaPlugins) {
for (const resourceFile of resourceFiles) { for (const resourceFile of resourceFiles) {
const target = resourceFile.$['target']; const target = resourceFile.$['target'];
if (resourceFile.$.src.split('.').pop() === 'aar') { if (resourceFile.$.src.split('.').pop() === 'aar') {
await (0, utils_fs_1.copy)((0, plugin_1.getFilePath)(config, p, resourceFile.$.src), (0, path_1.join)(pluginsPath, 'libs', target.split('/').pop())); await (0, fs_extra_1.copy)((0, plugin_1.getFilePath)(config, p, resourceFile.$.src), (0, path_1.join)(pluginsPath, 'libs', target.split('/').pop()));
} }
else if (target !== '.') { else if (target !== '.') {
await (0, utils_fs_1.copy)((0, plugin_1.getFilePath)(config, p, resourceFile.$.src), (0, path_1.join)(pluginsPath, target)); await (0, fs_extra_1.copy)((0, plugin_1.getFilePath)(config, p, resourceFile.$.src), (0, path_1.join)(pluginsPath, target));
} }
} }
} }
const libFiles = (0, plugin_1.getPlatformElement)(p, platform, 'lib-file'); const libFiles = (0, plugin_1.getPlatformElement)(p, platform, 'lib-file');
for (const libFile of libFiles) { for (const libFile of libFiles) {
await (0, utils_fs_1.copy)((0, plugin_1.getFilePath)(config, p, libFile.$.src), (0, path_1.join)(pluginsPath, 'libs', libFile.$.src.split('/').pop())); await (0, fs_extra_1.copy)((0, plugin_1.getFilePath)(config, p, libFile.$.src), (0, path_1.join)(pluginsPath, 'libs', libFile.$.src.split('/').pop()));
} }
} }
} }
} }
async function removePluginsNativeFiles(config) { async function removePluginsNativeFiles(config) {
await (0, utils_fs_1.remove)(config.android.cordovaPluginsDirAbs); await (0, fs_extra_1.remove)(config.android.cordovaPluginsDirAbs);
await (0, template_1.extractTemplate)(config.cli.assets.android.cordovaPluginsTemplateArchiveAbs, config.android.cordovaPluginsDirAbs); await (0, template_1.extractTemplate)(config.cli.assets.android.cordovaPluginsTemplateArchiveAbs, config.android.cordovaPluginsDirAbs);
} }
async function getPluginsTask(config) { async function getPluginsTask(config) {
@ -307,8 +303,8 @@ async function getPluginsTask(config) {
async function getVariablesGradleFile(config) { async function getVariablesGradleFile(config) {
const variablesFile = (0, path_1.resolve)(config.android.platformDirAbs, 'variables.gradle'); const variablesFile = (0, path_1.resolve)(config.android.platformDirAbs, 'variables.gradle');
let variablesGradle = ''; let variablesGradle = '';
if (await (0, utils_fs_1.pathExists)(variablesFile)) { if (await (0, fs_extra_1.pathExists)(variablesFile)) {
variablesGradle = await (0, utils_fs_1.readFile)(variablesFile, { encoding: 'utf-8' }); variablesGradle = await (0, fs_extra_1.readFile)(variablesFile, { encoding: 'utf-8' });
} }
return variablesGradle; return variablesGradle;
} }

View file

@ -2,8 +2,8 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.parseApkNameFromFlavor = exports.checkJDKMajorVersion = exports.resolvePlatform = exports.checkPlatformVersions = exports.getAddedPlatforms = exports.getPlatformTargetName = exports.promptForPlatformTarget = exports.promptForPlatform = exports.isValidEnterprisePlatform = exports.getKnownEnterprisePlatforms = exports.isValidCommunityPlatform = exports.getKnownCommunityPlatforms = exports.isValidPlatform = exports.getKnownPlatforms = exports.selectPlatforms = exports.getProjectPlatformDirectory = exports.getCLIVersion = exports.getCoreVersion = exports.getCapacitorPackageVersion = exports.requireCapacitorPackage = exports.getCapacitorPackage = exports.runTask = exports.runPlatformHook = exports.runHooks = exports.wait = exports.checkAppName = exports.checkAppId = exports.checkAppDir = exports.checkAppConfig = exports.checkCapacitorPlatform = exports.checkPackage = exports.checkWebDir = exports.check = void 0; exports.parseApkNameFromFlavor = exports.checkJDKMajorVersion = exports.resolvePlatform = exports.checkPlatformVersions = exports.getAddedPlatforms = exports.getPlatformTargetName = exports.promptForPlatformTarget = exports.promptForPlatform = exports.isValidEnterprisePlatform = exports.getKnownEnterprisePlatforms = exports.isValidCommunityPlatform = exports.getKnownCommunityPlatforms = exports.isValidPlatform = exports.getKnownPlatforms = exports.selectPlatforms = exports.getProjectPlatformDirectory = exports.getCLIVersion = exports.getCoreVersion = exports.getCapacitorPackageVersion = exports.requireCapacitorPackage = exports.getCapacitorPackage = exports.runTask = exports.runPlatformHook = exports.runHooks = exports.wait = exports.checkAppName = exports.checkAppId = exports.checkAppDir = exports.checkAppConfig = exports.checkCapacitorPlatform = exports.checkPackage = exports.checkWebDir = exports.check = void 0;
const tslib_1 = require("tslib"); const tslib_1 = require("tslib");
const utils_fs_1 = require("@ionic/utils-fs");
const utils_terminal_1 = require("@ionic/utils-terminal"); const utils_terminal_1 = require("@ionic/utils-terminal");
const fs_extra_1 = require("fs-extra");
const path_1 = require("path"); const path_1 = require("path");
const colors_1 = tslib_1.__importDefault(require("./colors")); const colors_1 = tslib_1.__importDefault(require("./colors"));
const errors_1 = require("./errors"); const errors_1 = require("./errors");
@ -13,8 +13,8 @@ const monorepotools_1 = require("./util/monorepotools");
const node_1 = require("./util/node"); const node_1 = require("./util/node");
const subprocess_1 = require("./util/subprocess"); const subprocess_1 = require("./util/subprocess");
async function check(checks) { async function check(checks) {
const results = await Promise.all(checks.map(f => f())); const results = await Promise.all(checks.map((f) => f()));
const errors = results.filter(r => r != null); const errors = results.filter((r) => r != null);
if (errors.length > 0) { if (errors.length > 0) {
throw errors.join('\n'); throw errors.join('\n');
} }
@ -30,11 +30,11 @@ async function checkWebDir(config) {
if (invalidFolders.includes(config.app.webDir)) { if (invalidFolders.includes(config.app.webDir)) {
return `"${config.app.webDir}" is not a valid value for webDir`; return `"${config.app.webDir}" is not a valid value for webDir`;
} }
if (!(await (0, utils_fs_1.pathExists)(config.app.webDirAbs))) { if (!(await (0, fs_extra_1.pathExists)(config.app.webDirAbs))) {
return (`Could not find the web assets directory: ${colors_1.default.strong((0, utils_terminal_1.prettyPath)(config.app.webDirAbs))}.\n` + return (`Could not find the web assets directory: ${colors_1.default.strong((0, utils_terminal_1.prettyPath)(config.app.webDirAbs))}.\n` +
`Please create it and make sure it has an ${colors_1.default.strong('index.html')} file. You can change the path of this directory in ${colors_1.default.strong(config.app.extConfigName)} (${colors_1.default.input('webDir')} option). You may need to compile the web assets for your app (typically ${colors_1.default.input('npm run build')}). More info: ${colors_1.default.strong('https://capacitorjs.com/docs/basics/workflow#sync-your-project')}`); `Please create it and make sure it has an ${colors_1.default.strong('index.html')} file. You can change the path of this directory in ${colors_1.default.strong(config.app.extConfigName)} (${colors_1.default.input('webDir')} option). You may need to compile the web assets for your app (typically ${colors_1.default.input('npm run build')}). More info: ${colors_1.default.strong('https://capacitorjs.com/docs/basics/workflow#sync-your-project')}`);
} }
if (!(await (0, utils_fs_1.pathExists)((0, path_1.join)(config.app.webDirAbs, 'index.html')))) { if (!(await (0, fs_extra_1.pathExists)((0, path_1.join)(config.app.webDirAbs, 'index.html')))) {
return (`The web assets directory (${colors_1.default.strong((0, utils_terminal_1.prettyPath)(config.app.webDirAbs))}) must contain an ${colors_1.default.strong('index.html')} file.\n` + return (`The web assets directory (${colors_1.default.strong((0, utils_terminal_1.prettyPath)(config.app.webDirAbs))}) must contain an ${colors_1.default.strong('index.html')} file.\n` +
`It will be the entry point for the web portion of the Capacitor app.`); `It will be the entry point for the web portion of the Capacitor app.`);
} }
@ -42,8 +42,8 @@ async function checkWebDir(config) {
} }
exports.checkWebDir = checkWebDir; exports.checkWebDir = checkWebDir;
async function checkPackage() { async function checkPackage() {
if (!(await (0, utils_fs_1.pathExists)('package.json'))) { if (!(await (0, fs_extra_1.pathExists)('package.json'))) {
if (await (0, utils_fs_1.pathExists)('project.json')) { if (await (0, fs_extra_1.pathExists)('project.json')) {
return null; return null;
} }
else { else {
@ -93,12 +93,20 @@ async function checkAppDir(config, dir) {
exports.checkAppDir = checkAppDir; exports.checkAppDir = checkAppDir;
async function checkAppId(config, id) { async function checkAppId(config, id) {
if (!id) { if (!id) {
return `Invalid App ID. Must be in Java package form with no dashes (ex: com.example.app)`; return `Invalid App ID. App ID is required and cannot be blank.`;
} }
if (/^[a-z][a-z0-9_]*(\.[a-z0-9_]+)+$/.test(id.toLowerCase())) { if (/^[a-zA-Z][\w]*(?:\.[a-zA-Z][\w]*)+$/.test(id.toLowerCase())) {
return null; return null;
} }
return `Invalid App ID "${id}". Must be in Java package form with no dashes (ex: com.example.app)`; return `
Invalid App ID "${id}". Your App ID must meet the following requirements to be valid on both iOS and Android:
- Must be in Java package form with no dashes (ex: com.example.app)
- It must have at least two segments (one or more dots).
- Each segment must start with a letter.
- All characters must be alphanumeric or an underscore [a-zA-Z][a-zA-Z0-9]+.
If you would like to skip validation, run "cap init" with the "--skip-appid-validation" flag.
`;
} }
exports.checkAppId = checkAppId; exports.checkAppId = checkAppId;
async function checkAppName(config, name) { async function checkAppName(config, name) {
@ -110,15 +118,15 @@ async function checkAppName(config, name) {
} }
exports.checkAppName = checkAppName; exports.checkAppName = checkAppName;
async function wait(time) { async function wait(time) {
return new Promise(resolve => setTimeout(resolve, time)); return new Promise((resolve) => setTimeout(resolve, time));
} }
exports.wait = wait; exports.wait = wait;
async function runHooks(config, platformName, dir, hook) { async function runHooks(config, platformName, dir, hook) {
await runPlatformHook(config, platformName, dir, hook); await runPlatformHook(config, platformName, dir, hook);
const allPlugins = await (0, plugin_1.getPlugins)(config, platformName); const allPlugins = await (0, plugin_1.getPlugins)(config, platformName);
allPlugins.forEach(async (p) => { for (const p of allPlugins) {
await runPlatformHook(config, platformName, p.rootPath, hook); await runPlatformHook(config, platformName, p.rootPath, hook);
}); }
} }
exports.runHooks = runHooks; exports.runHooks = runHooks;
async function runPlatformHook(config, platformName, platformDir, hook) { async function runPlatformHook(config, platformName, platformDir, hook) {
@ -126,10 +134,10 @@ async function runPlatformHook(config, platformName, platformDir, hook) {
const { spawn } = await Promise.resolve().then(() => tslib_1.__importStar(require('child_process'))); const { spawn } = await Promise.resolve().then(() => tslib_1.__importStar(require('child_process')));
let pkg; let pkg;
if ((0, monorepotools_1.isNXMonorepo)(platformDir)) { if ((0, monorepotools_1.isNXMonorepo)(platformDir)) {
pkg = await (0, utils_fs_1.readJSON)((0, path_1.join)((0, monorepotools_1.findNXMonorepoRoot)(platformDir), 'package.json')); pkg = await (0, fs_extra_1.readJSON)((0, path_1.join)((0, monorepotools_1.findNXMonorepoRoot)(platformDir), 'package.json'));
} }
else { else {
pkg = await (0, utils_fs_1.readJSON)((0, path_1.join)(platformDir, 'package.json')); pkg = await (0, fs_extra_1.readJSON)((0, path_1.join)(platformDir, 'package.json'));
} }
const cmd = (_a = pkg.scripts) === null || _a === void 0 ? void 0 : _a[hook]; const cmd = (_a = pkg.scripts) === null || _a === void 0 ? void 0 : _a[hook];
if (!cmd) { if (!cmd) {
@ -149,10 +157,15 @@ async function runPlatformHook(config, platformName, platformDir, hook) {
...process.env, ...process.env,
}, },
}); });
p.on('close', () => { p.on('close', (code) => {
resolve(); if (code === 0) {
resolve();
}
else {
reject(new Error(`${hook} hook on ${platformName} failed with error code: ${code} while running command: ${cmd}`));
}
}); });
p.on('error', err => { p.on('error', (err) => {
reject(err); reject(err);
}); });
}); });
@ -177,7 +190,7 @@ async function getCapacitorPackage(config, name) {
if (!packagePath) { if (!packagePath) {
return null; return null;
} }
return (0, utils_fs_1.readJSON)(packagePath); return (0, fs_extra_1.readJSON)(packagePath);
} }
exports.getCapacitorPackage = getCapacitorPackage; exports.getCapacitorPackage = getCapacitorPackage;
async function requireCapacitorPackage(config, name) { async function requireCapacitorPackage(config, name) {
@ -214,7 +227,7 @@ function getPlatformDirectory(config, platform) {
} }
async function getProjectPlatformDirectory(config, platform) { async function getProjectPlatformDirectory(config, platform) {
const platformPath = getPlatformDirectory(config, platform); const platformPath = getPlatformDirectory(config, platform);
if (platformPath && (await (0, utils_fs_1.pathExists)(platformPath))) { if (platformPath && (await (0, fs_extra_1.pathExists)(platformPath))) {
return platformPath; return platformPath;
} }
return null; return null;
@ -229,8 +242,7 @@ async function selectPlatforms(config, selectedPlatformName) {
} }
else if (!(await getProjectPlatformDirectory(config, platformName))) { else if (!(await getProjectPlatformDirectory(config, platformName))) {
if (platformName === 'web') { if (platformName === 'web') {
(0, errors_1.fatal)(`Could not find the web platform directory.\n` + (0, errors_1.fatal)(`Could not find the web platform directory.\n` + `Make sure ${colors_1.default.strong(config.app.webDir)} exists.`);
`Make sure ${colors_1.default.strong(config.app.webDir)} exists.`);
} }
(0, errors_1.fatal)(`${colors_1.default.strong(platformName)} platform has not been added yet.\n` + (0, errors_1.fatal)(`${colors_1.default.strong(platformName)} platform has not been added yet.\n` +
`See the docs for adding the ${colors_1.default.strong(platformName)} platform: ${colors_1.default.strong(`https://capacitorjs.com/docs/${platformName}#adding-the-${platformName}-platform`)}`); `See the docs for adding the ${colors_1.default.strong(platformName)} platform: ${colors_1.default.strong(`https://capacitorjs.com/docs/${platformName}#adding-the-${platformName}-platform`)}`);
@ -275,7 +287,7 @@ async function promptForPlatform(platforms, promptMessage, selectedPlatformName)
type: 'select', type: 'select',
name: 'mode', name: 'mode',
message: promptMessage, message: promptMessage,
choices: platforms.map(p => ({ title: p, value: p })), choices: platforms.map((p) => ({ title: p, value: p })),
}, },
], { onCancel: () => process.exit(1) }); ], { onCancel: () => process.exit(1) });
return answers.mode.toLowerCase().trim(); return answers.mode.toLowerCase().trim();
@ -283,15 +295,14 @@ async function promptForPlatform(platforms, promptMessage, selectedPlatformName)
const platformName = selectedPlatformName.toLowerCase().trim(); const platformName = selectedPlatformName.toLowerCase().trim();
if (!(await isValidPlatform(platformName))) { if (!(await isValidPlatform(platformName))) {
const knownPlatforms = await getKnownPlatforms(); const knownPlatforms = await getKnownPlatforms();
(0, errors_1.fatal)(`Invalid platform: ${colors_1.default.input(platformName)}.\n` + (0, errors_1.fatal)(`Invalid platform: ${colors_1.default.input(platformName)}.\n` + `Valid platforms include: ${knownPlatforms.join(', ')}`);
`Valid platforms include: ${knownPlatforms.join(', ')}`);
} }
return platformName; return platformName;
} }
exports.promptForPlatform = promptForPlatform; exports.promptForPlatform = promptForPlatform;
async function promptForPlatformTarget(targets, selectedTarget) { async function promptForPlatformTarget(targets, selectedTarget) {
const { prompt } = await Promise.resolve().then(() => tslib_1.__importStar(require('prompts'))); const { prompt } = await Promise.resolve().then(() => tslib_1.__importStar(require('prompts')));
const validTargets = targets.filter(t => t.id !== undefined); const validTargets = targets.filter((t) => t.id !== undefined);
if (!selectedTarget) { if (!selectedTarget) {
if (validTargets.length === 1) { if (validTargets.length === 1) {
return validTargets[0]; return validTargets[0];
@ -302,7 +313,7 @@ async function promptForPlatformTarget(targets, selectedTarget) {
type: 'select', type: 'select',
name: 'target', name: 'target',
message: 'Please choose a target device:', message: 'Please choose a target device:',
choices: validTargets.map(t => ({ choices: validTargets.map((t) => ({
title: `${getPlatformTargetName(t)} (${t.id})`, title: `${getPlatformTargetName(t)} (${t.id})`,
value: t, value: t,
})), })),
@ -312,19 +323,16 @@ async function promptForPlatformTarget(targets, selectedTarget) {
} }
} }
const targetID = selectedTarget.trim(); const targetID = selectedTarget.trim();
const target = targets.find(t => t.id === targetID); const target = targets.find((t) => t.id === targetID);
if (!target) { if (!target) {
(0, errors_1.fatal)(`Invalid target ID: ${colors_1.default.input(targetID)}.\n` + (0, errors_1.fatal)(`Invalid target ID: ${colors_1.default.input(targetID)}.\n` + `Valid targets are: ${targets.map((t) => t.id).join(', ')}`);
`Valid targets are: ${targets.map(t => t.id).join(', ')}`);
} }
return target; return target;
} }
exports.promptForPlatformTarget = promptForPlatformTarget; exports.promptForPlatformTarget = promptForPlatformTarget;
function getPlatformTargetName(target) { function getPlatformTargetName(target) {
var _a, _b, _c; var _a, _b, _c;
return `${(_c = (_b = (_a = target.name) !== null && _a !== void 0 ? _a : target.model) !== null && _b !== void 0 ? _b : target.id) !== null && _c !== void 0 ? _c : '?'}${target.virtual return `${(_c = (_b = (_a = target.name) !== null && _a !== void 0 ? _a : target.model) !== null && _b !== void 0 ? _b : target.id) !== null && _c !== void 0 ? _c : '?'}${target.virtual ? ` (${target.platform === 'ios' ? 'simulator' : 'emulator'})` : ''}`;
? ` (${target.platform === 'ios' ? 'simulator' : 'emulator'})`
: ''}`;
} }
exports.getPlatformTargetName = getPlatformTargetName; exports.getPlatformTargetName = getPlatformTargetName;
async function getAddedPlatforms(config) { async function getAddedPlatforms(config) {
@ -343,8 +351,7 @@ async function checkPlatformVersions(config, platform) {
const semver = await Promise.resolve().then(() => tslib_1.__importStar(require('semver'))); const semver = await Promise.resolve().then(() => tslib_1.__importStar(require('semver')));
const coreVersion = await getCoreVersion(config); const coreVersion = await getCoreVersion(config);
const platformVersion = await getCapacitorPackageVersion(config, platform); const platformVersion = await getCapacitorPackageVersion(config, platform);
if (semver.diff(coreVersion, platformVersion) === 'minor' || if (semver.diff(coreVersion, platformVersion) === 'minor' || semver.diff(coreVersion, platformVersion) === 'major') {
semver.diff(coreVersion, platformVersion) === 'major') {
log_1.logger.warn(`${colors_1.default.strong('@capacitor/core')}${colors_1.default.weak(`@${coreVersion}`)} version doesn't match ${colors_1.default.strong(`@capacitor/${platform}`)}${colors_1.default.weak(`@${platformVersion}`)} version.\n` + log_1.logger.warn(`${colors_1.default.strong('@capacitor/core')}${colors_1.default.weak(`@${coreVersion}`)} version doesn't match ${colors_1.default.strong(`@capacitor/${platform}`)}${colors_1.default.weak(`@${platformVersion}`)} version.\n` +
`Consider updating to a matching version, e.g. w/ ${colors_1.default.input(`npm install @capacitor/core@${platformVersion}`)}`); `Consider updating to a matching version, e.g. w/ ${colors_1.default.input(`npm install @capacitor/core@${platformVersion}`)}`);
} }
@ -386,9 +393,7 @@ async function checkJDKMajorVersion() {
if (typeof firstVersionNumber === 'number' && firstVersionNumber != 1) { if (typeof firstVersionNumber === 'number' && firstVersionNumber != 1) {
return firstVersionNumber; return firstVersionNumber;
} }
else if (typeof secondVersionNumber === 'number' && else if (typeof secondVersionNumber === 'number' && firstVersionNumber == 1 && secondVersionNumber < 9) {
firstVersionNumber == 1 &&
secondVersionNumber < 9) {
return secondVersionNumber; return secondVersionNumber;
} }
else { else {

View file

@ -1,9 +1,9 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.checkExternalConfig = exports.writeConfig = exports.loadConfig = exports.CONFIG_FILE_NAME_JSON = exports.CONFIG_FILE_NAME_JS = exports.CONFIG_FILE_NAME_TS = void 0; exports.writeConfig = exports.loadConfig = exports.CONFIG_FILE_NAME_JSON = exports.CONFIG_FILE_NAME_JS = exports.CONFIG_FILE_NAME_TS = void 0;
const tslib_1 = require("tslib"); const tslib_1 = require("tslib");
const utils_fs_1 = require("@ionic/utils-fs");
const debug_1 = tslib_1.__importDefault(require("debug")); const debug_1 = tslib_1.__importDefault(require("debug"));
const fs_extra_1 = require("fs-extra");
const path_1 = require("path"); const path_1 = require("path");
const colors_1 = tslib_1.__importDefault(require("./colors")); const colors_1 = tslib_1.__importDefault(require("./colors"));
const common_1 = require("./common"); const common_1 = require("./common");
@ -28,7 +28,7 @@ async function loadConfig() {
var _a, _b; var _a, _b;
if ((0, monorepotools_1.isNXMonorepo)(appRootDir)) { if ((0, monorepotools_1.isNXMonorepo)(appRootDir)) {
const rootOfNXMonorepo = (0, monorepotools_1.findNXMonorepoRoot)(appRootDir); const rootOfNXMonorepo = (0, monorepotools_1.findNXMonorepoRoot)(appRootDir);
const pkgJSONOfMonorepoRoot = await (0, fn_1.tryFn)(utils_fs_1.readJSON, (0, path_1.resolve)(rootOfNXMonorepo, 'package.json')); const pkgJSONOfMonorepoRoot = await (0, fn_1.tryFn)(fs_extra_1.readJSON, (0, path_1.resolve)(rootOfNXMonorepo, 'package.json'));
const devDependencies = (_a = pkgJSONOfMonorepoRoot === null || pkgJSONOfMonorepoRoot === void 0 ? void 0 : pkgJSONOfMonorepoRoot.devDependencies) !== null && _a !== void 0 ? _a : {}; const devDependencies = (_a = pkgJSONOfMonorepoRoot === null || pkgJSONOfMonorepoRoot === void 0 ? void 0 : pkgJSONOfMonorepoRoot.devDependencies) !== null && _a !== void 0 ? _a : {};
const dependencies = (_b = pkgJSONOfMonorepoRoot === null || pkgJSONOfMonorepoRoot === void 0 ? void 0 : pkgJSONOfMonorepoRoot.dependencies) !== null && _b !== void 0 ? _b : {}; const dependencies = (_b = pkgJSONOfMonorepoRoot === null || pkgJSONOfMonorepoRoot === void 0 ? void 0 : pkgJSONOfMonorepoRoot.dependencies) !== null && _b !== void 0 ? _b : {};
return { return {
@ -53,7 +53,7 @@ async function loadConfig() {
appName, appName,
webDir, webDir,
webDirAbs: (0, path_1.resolve)(appRootDir, webDir), webDirAbs: (0, path_1.resolve)(appRootDir, webDir),
package: (_d = (await (0, fn_1.tryFn)(utils_fs_1.readJSON, (0, path_1.resolve)(appRootDir, 'package.json')))) !== null && _d !== void 0 ? _d : { package: (_d = (await (0, fn_1.tryFn)(fs_extra_1.readJSON, (0, path_1.resolve)(appRootDir, 'package.json')))) !== null && _d !== void 0 ? _d : {
name: appName, name: appName,
version: '1.0.0', version: '1.0.0',
...depsForNx, ...depsForNx,
@ -68,11 +68,11 @@ exports.loadConfig = loadConfig;
async function writeConfig(extConfig, extConfigFilePath) { async function writeConfig(extConfig, extConfigFilePath) {
switch ((0, path_1.extname)(extConfigFilePath)) { switch ((0, path_1.extname)(extConfigFilePath)) {
case '.json': { case '.json': {
await (0, utils_fs_1.writeJSON)(extConfigFilePath, extConfig, { spaces: 2 }); await (0, fs_extra_1.writeJSON)(extConfigFilePath, extConfig, { spaces: 2 });
break; break;
} }
case '.ts': { case '.ts': {
await (0, utils_fs_1.writeFile)(extConfigFilePath, formatConfigTS(extConfig)); await (0, fs_extra_1.writeFile)(extConfigFilePath, formatConfigTS(extConfig));
break; break;
} }
} }
@ -88,9 +88,7 @@ async function loadExtConfigTS(rootDir, extConfigName, extConfigFilePath) {
} }
const ts = require(tsPath); // eslint-disable-line @typescript-eslint/no-var-requires const ts = require(tsPath); // eslint-disable-line @typescript-eslint/no-var-requires
const extConfigObject = (0, node_1.requireTS)(ts, extConfigFilePath); const extConfigObject = (0, node_1.requireTS)(ts, extConfigFilePath);
const extConfig = extConfigObject.default const extConfig = extConfigObject.default ? await extConfigObject.default : extConfigObject;
? await extConfigObject.default
: extConfigObject;
return { return {
extConfigType: 'ts', extConfigType: 'ts',
extConfigName, extConfigName,
@ -122,11 +120,11 @@ async function loadExtConfigJS(rootDir, extConfigName, extConfigFilePath) {
async function loadExtConfig(rootDir) { async function loadExtConfig(rootDir) {
var _a; var _a;
const extConfigFilePathTS = (0, path_1.resolve)(rootDir, exports.CONFIG_FILE_NAME_TS); const extConfigFilePathTS = (0, path_1.resolve)(rootDir, exports.CONFIG_FILE_NAME_TS);
if (await (0, utils_fs_1.pathExists)(extConfigFilePathTS)) { if (await (0, fs_extra_1.pathExists)(extConfigFilePathTS)) {
return loadExtConfigTS(rootDir, exports.CONFIG_FILE_NAME_TS, extConfigFilePathTS); return loadExtConfigTS(rootDir, exports.CONFIG_FILE_NAME_TS, extConfigFilePathTS);
} }
const extConfigFilePathJS = (0, path_1.resolve)(rootDir, exports.CONFIG_FILE_NAME_JS); const extConfigFilePathJS = (0, path_1.resolve)(rootDir, exports.CONFIG_FILE_NAME_JS);
if (await (0, utils_fs_1.pathExists)(extConfigFilePathJS)) { if (await (0, fs_extra_1.pathExists)(extConfigFilePathJS)) {
return loadExtConfigJS(rootDir, exports.CONFIG_FILE_NAME_JS, extConfigFilePathJS); return loadExtConfigJS(rootDir, exports.CONFIG_FILE_NAME_JS, extConfigFilePathJS);
} }
const extConfigFilePath = (0, path_1.resolve)(rootDir, exports.CONFIG_FILE_NAME_JSON); const extConfigFilePath = (0, path_1.resolve)(rootDir, exports.CONFIG_FILE_NAME_JSON);
@ -134,7 +132,7 @@ async function loadExtConfig(rootDir) {
extConfigType: 'json', extConfigType: 'json',
extConfigName: exports.CONFIG_FILE_NAME_JSON, extConfigName: exports.CONFIG_FILE_NAME_JSON,
extConfigFilePath: extConfigFilePath, extConfigFilePath: extConfigFilePath,
extConfig: (_a = (await (0, fn_1.tryFn)(utils_fs_1.readJSON, extConfigFilePath))) !== null && _a !== void 0 ? _a : {}, extConfig: (_a = (await (0, fn_1.tryFn)(fs_extra_1.readJSON, extConfigFilePath))) !== null && _a !== void 0 ? _a : {},
}; };
} }
async function loadCLIConfig(rootDir) { async function loadCLIConfig(rootDir) {
@ -162,7 +160,7 @@ async function loadCLIConfig(rootDir) {
cordovaPluginsTemplateArchiveAbs: (0, path_1.resolve)(assetsDirAbs, androidCordovaPluginsTemplateArchive), cordovaPluginsTemplateArchiveAbs: (0, path_1.resolve)(assetsDirAbs, androidCordovaPluginsTemplateArchive),
}, },
}, },
package: await (0, utils_fs_1.readJSON)((0, path_1.resolve)(rootDir, 'package.json')), package: await (0, fs_extra_1.readJSON)((0, path_1.resolve)(rootDir, 'package.json')),
os: determineOS(process.platform), os: determineOS(process.platform),
}; };
} }
@ -196,7 +194,7 @@ async function loadAndroidConfig(rootDir, extConfig, cliConfig) {
}; };
return { return {
name, name,
minVersion: '22', minVersion: '23',
studioPath, studioPath,
platformDir, platformDir,
platformDirAbs, platformDirAbs,
@ -222,7 +220,7 @@ async function loadAndroidConfig(rootDir, extConfig, cliConfig) {
}; };
} }
async function loadIOSConfig(rootDir, extConfig) { async function loadIOSConfig(rootDir, extConfig) {
var _a, _b, _c, _d; var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
const name = 'ios'; const name = 'ios';
const platformDir = (_b = (_a = extConfig.ios) === null || _a === void 0 ? void 0 : _a.path) !== null && _b !== void 0 ? _b : 'ios'; const platformDir = (_b = (_a = extConfig.ios) === null || _a === void 0 ? void 0 : _a.path) !== null && _b !== void 0 ? _b : 'ios';
const platformDirAbs = (0, path_1.resolve)(rootDir, platformDir); const platformDirAbs = (0, path_1.resolve)(rootDir, platformDir);
@ -237,9 +235,15 @@ async function loadIOSConfig(rootDir, extConfig) {
const podPath = (0, promise_1.lazy)(() => determineGemfileOrCocoapodPath(rootDir, platformDirAbs, nativeProjectDirAbs)); const podPath = (0, promise_1.lazy)(() => determineGemfileOrCocoapodPath(rootDir, platformDirAbs, nativeProjectDirAbs));
const webDirAbs = (0, promise_1.lazy)(() => determineIOSWebDirAbs(nativeProjectDirAbs, nativeTargetDirAbs, nativeXcodeProjDirAbs)); const webDirAbs = (0, promise_1.lazy)(() => determineIOSWebDirAbs(nativeProjectDirAbs, nativeTargetDirAbs, nativeXcodeProjDirAbs));
const cordovaPluginsDir = 'capacitor-cordova-ios-plugins'; const cordovaPluginsDir = 'capacitor-cordova-ios-plugins';
const buildOptions = {
exportMethod: (_f = (_e = extConfig.ios) === null || _e === void 0 ? void 0 : _e.buildOptions) === null || _f === void 0 ? void 0 : _f.exportMethod,
xcodeSigningStyle: (_h = (_g = extConfig.ios) === null || _g === void 0 ? void 0 : _g.buildOptions) === null || _h === void 0 ? void 0 : _h.signingStyle,
signingCertificate: (_k = (_j = extConfig.ios) === null || _j === void 0 ? void 0 : _j.buildOptions) === null || _k === void 0 ? void 0 : _k.signingCertificate,
provisioningProfile: (_m = (_l = extConfig.ios) === null || _l === void 0 ? void 0 : _l.buildOptions) === null || _m === void 0 ? void 0 : _m.provisioningProfile,
};
return { return {
name, name,
minVersion: '13.0', minVersion: '14.0',
platformDir, platformDir,
platformDirAbs, platformDirAbs,
scheme, scheme,
@ -256,6 +260,7 @@ async function loadIOSConfig(rootDir, extConfig) {
webDir: (0, promise_1.lazy)(async () => (0, path_1.relative)(platformDirAbs, await webDirAbs)), webDir: (0, promise_1.lazy)(async () => (0, path_1.relative)(platformDirAbs, await webDirAbs)),
webDirAbs, webDirAbs,
podPath, podPath,
buildOptions,
}; };
} }
async function loadWebConfig(rootDir, webDir) { async function loadWebConfig(rootDir, webDir) {
@ -285,7 +290,7 @@ async function determineIOSWebDirAbs(nativeProjectDirAbs, nativeTargetDirAbs, na
const re = /path\s=\spublic[\s\S]+?sourceTree\s=\s([^;]+)/; const re = /path\s=\spublic[\s\S]+?sourceTree\s=\s([^;]+)/;
const pbxprojPath = (0, path_1.resolve)(nativeXcodeProjDirAbs, 'project.pbxproj'); const pbxprojPath = (0, path_1.resolve)(nativeXcodeProjDirAbs, 'project.pbxproj');
try { try {
const pbxproj = await (0, utils_fs_1.readFile)(pbxprojPath, { encoding: 'utf8' }); const pbxproj = await (0, fs_extra_1.readFile)(pbxprojPath, { encoding: 'utf8' });
const m = pbxproj.match(re); const m = pbxproj.match(re);
if (m && m[1] === 'SOURCE_ROOT') { if (m && m[1] === 'SOURCE_ROOT') {
log_1.logger.warn(`Using the iOS project root for the ${colors_1.default.strong('public')} directory is deprecated.\n` + log_1.logger.warn(`Using the iOS project root for the ${colors_1.default.strong('public')} directory is deprecated.\n` +
@ -309,7 +314,7 @@ async function determineAndroidStudioPath(os) {
const { runCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./util/subprocess'))); const { runCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./util/subprocess')));
let p = 'C:\\Program Files\\Android\\Android Studio\\bin\\studio64.exe'; let p = 'C:\\Program Files\\Android\\Android Studio\\bin\\studio64.exe';
try { try {
if (!(await (0, utils_fs_1.pathExists)(p))) { if (!(await (0, fs_extra_1.pathExists)(p))) {
let commandResult = await runCommand('REG', [ let commandResult = await runCommand('REG', [
'QUERY', 'QUERY',
'HKEY_LOCAL_MACHINE\\SOFTWARE\\Android Studio', 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Android Studio',
@ -339,13 +344,13 @@ async function determineGemfileOrCocoapodPath(rootDir, platformDir, nativeProjec
return process.env.CAPACITOR_COCOAPODS_PATH; return process.env.CAPACITOR_COCOAPODS_PATH;
} }
let gemfilePath = ''; let gemfilePath = '';
if (await (0, utils_fs_1.pathExists)((0, path_1.resolve)(rootDir, 'Gemfile'))) { if (await (0, fs_extra_1.pathExists)((0, path_1.resolve)(rootDir, 'Gemfile'))) {
gemfilePath = (0, path_1.resolve)(rootDir, 'Gemfile'); gemfilePath = (0, path_1.resolve)(rootDir, 'Gemfile');
} }
else if (await (0, utils_fs_1.pathExists)((0, path_1.resolve)(platformDir, 'Gemfile'))) { else if (await (0, fs_extra_1.pathExists)((0, path_1.resolve)(platformDir, 'Gemfile'))) {
gemfilePath = (0, path_1.resolve)(platformDir, 'Gemfile'); gemfilePath = (0, path_1.resolve)(platformDir, 'Gemfile');
} }
else if (await (0, utils_fs_1.pathExists)((0, path_1.resolve)(nativeProjectDirAbs, 'Gemfile'))) { else if (await (0, fs_extra_1.pathExists)((0, path_1.resolve)(nativeProjectDirAbs, 'Gemfile'))) {
gemfilePath = (0, path_1.resolve)(nativeProjectDirAbs, 'Gemfile'); gemfilePath = (0, path_1.resolve)(nativeProjectDirAbs, 'Gemfile');
} }
const appSpecificGemfileExists = gemfilePath != ''; const appSpecificGemfileExists = gemfilePath != '';
@ -362,7 +367,7 @@ async function determineGemfileOrCocoapodPath(rootDir, platformDir, nativeProjec
} }
} }
try { try {
const gemfileText = (await (0, utils_fs_1.readFile)(gemfilePath)).toString(); const gemfileText = (await (0, fs_extra_1.readFile)(gemfilePath)).toString();
if (!gemfileText) { if (!gemfileText) {
return 'pod'; return 'pod';
} }
@ -386,13 +391,3 @@ const config: CapacitorConfig = ${(0, js_1.formatJSObject)(extConfig)};
export default config;\n`; export default config;\n`;
} }
function checkExternalConfig(config) {
if (typeof config.extConfig.bundledWebRuntime !== 'undefined') {
let actionMessage = `Can be safely deleted.`;
if (config.extConfig.bundledWebRuntime === true) {
actionMessage = `Please, use a bundler to bundle Capacitor and its plugins.`;
}
log_1.logger.warn(`The ${colors_1.default.strong('bundledWebRuntime')} configuration option has been deprecated. ${actionMessage}`);
}
}
exports.checkExternalConfig = checkExternalConfig;

View file

@ -2,7 +2,7 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.writeCordovaAndroidManifest = exports.getCordovaPreferences = exports.needsStaticPod = exports.getIncompatibleCordovaPlugins = exports.checkPluginDependencies = exports.logCordovaManualSteps = exports.getCordovaPlugins = exports.handleCordovaPluginsJS = exports.autoGenerateConfig = exports.removePluginFiles = exports.createEmptyCordovaJS = exports.copyCordovaJS = exports.copyPluginsJS = exports.generateCordovaPluginsJSFile = void 0; exports.writeCordovaAndroidManifest = exports.getCordovaPreferences = exports.needsStaticPod = exports.getIncompatibleCordovaPlugins = exports.checkPluginDependencies = exports.logCordovaManualSteps = exports.getCordovaPlugins = exports.handleCordovaPluginsJS = exports.autoGenerateConfig = exports.removePluginFiles = exports.createEmptyCordovaJS = exports.copyCordovaJS = exports.copyPluginsJS = exports.generateCordovaPluginsJSFile = void 0;
const tslib_1 = require("tslib"); const tslib_1 = require("tslib");
const utils_fs_1 = require("@ionic/utils-fs"); const fs_extra_1 = require("fs-extra");
const path_1 = require("path"); const path_1 = require("path");
const plist_1 = tslib_1.__importDefault(require("plist")); const plist_1 = tslib_1.__importDefault(require("plist"));
const prompts_1 = tslib_1.__importDefault(require("prompts")); const prompts_1 = tslib_1.__importDefault(require("prompts"));
@ -21,7 +21,7 @@ const xml_1 = require("./util/xml");
function generateCordovaPluginsJSFile(config, plugins, platform) { function generateCordovaPluginsJSFile(config, plugins, platform) {
const pluginModules = []; const pluginModules = [];
const pluginExports = []; const pluginExports = [];
plugins.map(p => { plugins.map((p) => {
const pluginId = p.xml.$.id; const pluginId = p.xml.$.id;
const jsModules = (0, plugin_1.getJSModules)(p, platform); const jsModules = (0, plugin_1.getJSModules)(p, platform);
jsModules.map((jsModule) => { jsModules.map((jsModule) => {
@ -60,9 +60,7 @@ function generateCordovaPluginsJSFile(config, plugins, platform) {
merge: mergeKey, merge: mergeKey,
// mimics Cordova's module name logic if the name attr is missing // mimics Cordova's module name logic if the name attr is missing
pluginContent: `{ pluginContent: `{
"id": "${pluginId + "id": "${pluginId + '.' + (jsModule.$.name || jsModule.$.src.match(/([^/]+)\.js/)[1])}",
'.' +
(jsModule.$.name || jsModule.$.src.match(/([^/]+)\.js/)[1])}",
"file": "plugins/${pluginId}/${jsModule.$.src}", "file": "plugins/${pluginId}/${jsModule.$.src}",
"pluginId": "${pluginId}"${clobbersModule}${mergesModule}${runsModule} "pluginId": "${pluginId}"${clobbersModule}${mergesModule}${runsModule}
}`, }`,
@ -80,7 +78,7 @@ function generateCordovaPluginsJSFile(config, plugins, platform) {
: a.clobber || b.clobber // Clobbers before anything else : a.clobber || b.clobber // Clobbers before anything else
? b.clobber.localeCompare(a.clobber) ? b.clobber.localeCompare(a.clobber)
: a.merge.localeCompare(b.merge)) : a.merge.localeCompare(b.merge))
.map(e => e.pluginContent) .map((e) => e.pluginContent)
.join(',\n ')} .join(',\n ')}
]; ];
module.exports.metadata = module.exports.metadata =
@ -104,51 +102,49 @@ async function copyPluginsJS(config, cordovaPlugins, platform) {
await Promise.all(cordovaPlugins.map(async (p) => { await Promise.all(cordovaPlugins.map(async (p) => {
const pluginId = p.xml.$.id; const pluginId = p.xml.$.id;
const pluginDir = (0, path_1.join)(pluginsDir, pluginId, 'www'); const pluginDir = (0, path_1.join)(pluginsDir, pluginId, 'www');
await (0, utils_fs_1.ensureDir)(pluginDir); await (0, fs_extra_1.ensureDir)(pluginDir);
const jsModules = (0, plugin_1.getJSModules)(p, platform); const jsModules = (0, plugin_1.getJSModules)(p, platform);
await Promise.all(jsModules.map(async (jsModule) => { await Promise.all(jsModules.map(async (jsModule) => {
const filePath = (0, path_1.join)(webDir, 'plugins', pluginId, jsModule.$.src); const filePath = (0, path_1.join)(webDir, 'plugins', pluginId, jsModule.$.src);
await (0, utils_fs_1.copy)((0, path_1.join)(p.rootPath, jsModule.$.src), filePath); await (0, fs_extra_1.copy)((0, path_1.join)(p.rootPath, jsModule.$.src), filePath);
let data = await (0, utils_fs_1.readFile)(filePath, { encoding: 'utf-8' }); let data = await (0, fs_extra_1.readFile)(filePath, { encoding: 'utf-8' });
data = data.trim(); data = data.trim();
// mimics Cordova's module name logic if the name attr is missing // mimics Cordova's module name logic if the name attr is missing
const name = pluginId + const name = pluginId + '.' + (jsModule.$.name || (0, path_1.basename)(jsModule.$.src, (0, path_1.extname)(jsModule.$.src)));
'.' +
(jsModule.$.name ||
(0, path_1.basename)(jsModule.$.src, (0, path_1.extname)(jsModule.$.src)));
data = `cordova.define("${name}", function(require, exports, module) { \n${data}\n});`; data = `cordova.define("${name}", function(require, exports, module) { \n${data}\n});`;
data = data.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script\s*>/gi, ''); data = data.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script\s*>/gi, '');
await (0, utils_fs_1.writeFile)(filePath, data, { encoding: 'utf-8' }); await (0, fs_extra_1.writeFile)(filePath, data, { encoding: 'utf-8' });
})); }));
const assets = (0, plugin_1.getAssets)(p, platform); const assets = (0, plugin_1.getAssets)(p, platform);
await Promise.all(assets.map(async (asset) => { await Promise.all(assets.map(async (asset) => {
const filePath = (0, path_1.join)(webDir, asset.$.target); const filePath = (0, path_1.join)(webDir, asset.$.target);
await (0, utils_fs_1.copy)((0, path_1.join)(p.rootPath, asset.$.src), filePath); await (0, fs_extra_1.copy)((0, path_1.join)(p.rootPath, asset.$.src), filePath);
})); }));
})); }));
await (0, utils_fs_1.writeFile)(cordovaPluginsJSFile, generateCordovaPluginsJSFile(config, cordovaPlugins, platform)); await (0, fs_extra_1.writeFile)(cordovaPluginsJSFile, generateCordovaPluginsJSFile(config, cordovaPlugins, platform));
} }
exports.copyPluginsJS = copyPluginsJS; exports.copyPluginsJS = copyPluginsJS;
async function copyCordovaJS(config, platform) { async function copyCordovaJS(config, platform) {
const cordovaPath = (0, node_1.resolveNode)(config.app.rootDir, '@capacitor/core', 'cordova.js'); const cordovaPath = (0, node_1.resolveNode)(config.app.rootDir, '@capacitor/core', 'cordova.js');
if (!cordovaPath) { if (!cordovaPath) {
(0, errors_1.fatal)(`Unable to find ${colors_1.default.strong('node_modules/@capacitor/core/cordova.js')}.\n` + `Are you sure ${colors_1.default.strong('@capacitor/core')} is installed?`); (0, errors_1.fatal)(`Unable to find ${colors_1.default.strong('node_modules/@capacitor/core/cordova.js')}.\n` +
`Are you sure ${colors_1.default.strong('@capacitor/core')} is installed?`);
} }
return (0, utils_fs_1.copy)(cordovaPath, (0, path_1.join)(await getWebDir(config, platform), 'cordova.js')); return (0, fs_extra_1.copy)(cordovaPath, (0, path_1.join)(await getWebDir(config, platform), 'cordova.js'));
} }
exports.copyCordovaJS = copyCordovaJS; exports.copyCordovaJS = copyCordovaJS;
async function createEmptyCordovaJS(config, platform) { async function createEmptyCordovaJS(config, platform) {
const webDir = await getWebDir(config, platform); const webDir = await getWebDir(config, platform);
await (0, utils_fs_1.writeFile)((0, path_1.join)(webDir, 'cordova.js'), ''); await (0, fs_extra_1.writeFile)((0, path_1.join)(webDir, 'cordova.js'), '');
await (0, utils_fs_1.writeFile)((0, path_1.join)(webDir, 'cordova_plugins.js'), ''); await (0, fs_extra_1.writeFile)((0, path_1.join)(webDir, 'cordova_plugins.js'), '');
} }
exports.createEmptyCordovaJS = createEmptyCordovaJS; exports.createEmptyCordovaJS = createEmptyCordovaJS;
async function removePluginFiles(config, platform) { async function removePluginFiles(config, platform) {
const webDir = await getWebDir(config, platform); const webDir = await getWebDir(config, platform);
const pluginsDir = (0, path_1.join)(webDir, 'plugins'); const pluginsDir = (0, path_1.join)(webDir, 'plugins');
const cordovaPluginsJSFile = (0, path_1.join)(webDir, 'cordova_plugins.js'); const cordovaPluginsJSFile = (0, path_1.join)(webDir, 'cordova_plugins.js');
await (0, utils_fs_1.remove)(pluginsDir); await (0, fs_extra_1.remove)(pluginsDir);
await (0, utils_fs_1.remove)(cordovaPluginsJSFile); await (0, fs_extra_1.remove)(cordovaPluginsJSFile);
} }
exports.removePluginFiles = removePluginFiles; exports.removePluginFiles = removePluginFiles;
async function autoGenerateConfig(config, cordovaPlugins, platform) { async function autoGenerateConfig(config, cordovaPlugins, platform) {
@ -158,11 +154,11 @@ async function autoGenerateConfig(config, cordovaPlugins, platform) {
if (platform === 'ios') { if (platform === 'ios') {
xmlDir = config.ios.nativeTargetDirAbs; xmlDir = config.ios.nativeTargetDirAbs;
} }
await (0, utils_fs_1.ensureDir)(xmlDir); await (0, fs_extra_1.ensureDir)(xmlDir);
const cordovaConfigXMLFile = (0, path_1.join)(xmlDir, fileName); const cordovaConfigXMLFile = (0, path_1.join)(xmlDir, fileName);
await (0, utils_fs_1.remove)(cordovaConfigXMLFile); await (0, fs_extra_1.remove)(cordovaConfigXMLFile);
const pluginEntries = []; const pluginEntries = [];
cordovaPlugins.map(p => { cordovaPlugins.map((p) => {
const currentPlatform = (0, plugin_1.getPluginPlatform)(p, platform); const currentPlatform = (0, plugin_1.getPluginPlatform)(p, platform);
if (currentPlatform) { if (currentPlatform) {
const configFiles = currentPlatform['config-file']; const configFiles = currentPlatform['config-file'];
@ -207,7 +203,7 @@ async function autoGenerateConfig(config, cordovaPlugins, platform) {
${pluginEntriesString.join('')} ${pluginEntriesString.join('')}
${pluginPreferencesString.join('')} ${pluginPreferencesString.join('')}
</widget>`; </widget>`;
await (0, utils_fs_1.writeFile)(cordovaConfigXMLFile, content); await (0, fs_extra_1.writeFile)(cordovaConfigXMLFile, content);
} }
exports.autoGenerateConfig = autoGenerateConfig; exports.autoGenerateConfig = autoGenerateConfig;
async function getWebDir(config, platform) { async function getWebDir(config, platform) {
@ -221,7 +217,7 @@ async function getWebDir(config, platform) {
} }
async function handleCordovaPluginsJS(cordovaPlugins, config, platform) { async function handleCordovaPluginsJS(cordovaPlugins, config, platform) {
const webDir = await getWebDir(config, platform); const webDir = await getWebDir(config, platform);
await (0, utils_fs_1.mkdirp)(webDir); await (0, fs_extra_1.mkdirp)(webDir);
if (cordovaPlugins.length > 0) { if (cordovaPlugins.length > 0) {
(0, plugin_1.printPlugins)(cordovaPlugins, platform, 'cordova'); (0, plugin_1.printPlugins)(cordovaPlugins, platform, 'cordova');
await copyCordovaJS(config, platform); await copyCordovaJS(config, platform);
@ -243,11 +239,11 @@ async function getCordovaPlugins(config, platform) {
else if (platform === config.android.name) { else if (platform === config.android.name) {
plugins = await (0, common_1.getAndroidPlugins)(allPlugins); plugins = await (0, common_1.getAndroidPlugins)(allPlugins);
} }
return plugins.filter(p => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */); return plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */);
} }
exports.getCordovaPlugins = getCordovaPlugins; exports.getCordovaPlugins = getCordovaPlugins;
async function logCordovaManualSteps(cordovaPlugins, config, platform) { async function logCordovaManualSteps(cordovaPlugins, config, platform) {
cordovaPlugins.map(p => { cordovaPlugins.map((p) => {
const editConfig = (0, plugin_1.getPlatformElement)(p, platform, 'edit-config'); const editConfig = (0, plugin_1.getPlatformElement)(p, platform, 'edit-config');
const configFile = (0, plugin_1.getPlatformElement)(p, platform, 'config-file'); const configFile = (0, plugin_1.getPlatformElement)(p, platform, 'config-file');
editConfig.concat(configFile).map(async (configElement) => { editConfig.concat(configFile).map(async (configElement) => {
@ -268,26 +264,22 @@ async function logiOSPlist(configElement, config, plugin) {
if ((_a = config.app.extConfig.ios) === null || _a === void 0 ? void 0 : _a.scheme) { if ((_a = config.app.extConfig.ios) === null || _a === void 0 ? void 0 : _a.scheme) {
plistPath = (0, path_1.resolve)(config.ios.nativeProjectDirAbs, `${(_b = config.app.extConfig.ios) === null || _b === void 0 ? void 0 : _b.scheme}-Info.plist`); plistPath = (0, path_1.resolve)(config.ios.nativeProjectDirAbs, `${(_b = config.app.extConfig.ios) === null || _b === void 0 ? void 0 : _b.scheme}-Info.plist`);
} }
if (!(await (0, utils_fs_1.pathExists)(plistPath))) { if (!(await (0, fs_extra_1.pathExists)(plistPath))) {
plistPath = (0, path_1.resolve)(config.ios.nativeTargetDirAbs, 'Base.lproj', 'Info.plist'); plistPath = (0, path_1.resolve)(config.ios.nativeTargetDirAbs, 'Base.lproj', 'Info.plist');
} }
if (await (0, utils_fs_1.pathExists)(plistPath)) { if (await (0, fs_extra_1.pathExists)(plistPath)) {
const xmlMeta = await (0, xml_1.readXML)(plistPath); const xmlMeta = await (0, xml_1.readXML)(plistPath);
const data = await (0, utils_fs_1.readFile)(plistPath, { encoding: 'utf-8' }); const data = await (0, fs_extra_1.readFile)(plistPath, { encoding: 'utf-8' });
const trimmedPlistData = data.replace(/(\t|\r|\n)/g, ''); const trimmedPlistData = data.replace(/(\t|\r|\n)/g, '');
const plistData = plist_1.default.parse(data); const plistData = plist_1.default.parse(data);
const dict = xmlMeta.plist.dict.pop(); const dict = xmlMeta.plist.dict.pop();
if (!dict.key.includes(configElement.$.parent)) { if (!dict.key.includes(configElement.$.parent)) {
let xml = buildConfigFileXml(configElement); let xml = buildConfigFileXml(configElement);
xml = `<key>${configElement.$.parent}</key>${getConfigFileTagContent(xml)}`; xml = `<key>${configElement.$.parent}</key>${getConfigFileTagContent(xml)}`;
log_1.logger.warn(`Configuration required for ${colors_1.default.strong(plugin.id)}.\n` + log_1.logger.warn(`Configuration required for ${colors_1.default.strong(plugin.id)}.\n` + `Add the following to Info.plist:\n` + xml);
`Add the following to Info.plist:\n` +
xml);
} }
else if (configElement.array || configElement.dict) { else if (configElement.array || configElement.dict) {
if (configElement.array && if (configElement.array && configElement.array.length > 0 && configElement.array[0].string) {
configElement.array.length > 0 &&
configElement.array[0].string) {
let xml = ''; let xml = '';
configElement.array[0].string.map((element) => { configElement.array[0].string.map((element) => {
const d = plistData[configElement.$.parent]; const d = plistData[configElement.$.parent];
@ -356,8 +348,7 @@ async function logiOSPlist(configElement, config, plugin) {
parsedRequiredElements.push(rootOfRequiredElementsToAdd); parsedRequiredElements.push(rootOfRequiredElementsToAdd);
const doesContainElements = (requiredElementsArray, existingElementsArray) => { const doesContainElements = (requiredElementsArray, existingElementsArray) => {
for (const requiredElement of requiredElementsArray) { for (const requiredElement of requiredElementsArray) {
if (requiredElement.name === 'key' || if (requiredElement.name === 'key' || requiredElement.name === 'string') {
requiredElement.name === 'string') {
let foundMatch = false; let foundMatch = false;
for (const existingElement of existingElementsArray) { for (const existingElement of existingElementsArray) {
if (existingElement.name === requiredElement.name && if (existingElement.name === requiredElement.name &&
@ -375,8 +366,7 @@ async function logiOSPlist(configElement, config, plugin) {
let foundMatch = false; let foundMatch = false;
for (const existingElement of existingElementsArray) { for (const existingElement of existingElementsArray) {
if (existingElement.name === requiredElement.name) { if (existingElement.name === requiredElement.name) {
if ((requiredElement.children !== undefined) === if ((requiredElement.children !== undefined) === (existingElement.children !== undefined)) {
(existingElement.children !== undefined)) {
if (doesContainElements(requiredElement.children, existingElement.children)) { if (doesContainElements(requiredElement.children, existingElement.children)) {
foundMatch = true; foundMatch = true;
break; break;
@ -420,10 +410,10 @@ function removeOuterTags(str) {
const end = str.lastIndexOf('<'); const end = str.lastIndexOf('<');
return str.substring(start, end); return str.substring(start, end);
} }
async function checkPluginDependencies(plugins, platform) { async function checkPluginDependencies(plugins, platform, failOnMissingDeps = false) {
const pluginDeps = new Map(); const pluginDeps = new Map();
const cordovaPlugins = plugins.filter(p => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */); const cordovaPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */);
const incompatible = plugins.filter(p => (0, plugin_1.getPluginType)(p, platform) === 2 /* PluginType.Incompatible */); const incompatible = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 2 /* PluginType.Incompatible */);
await Promise.all(cordovaPlugins.map(async (p) => { await Promise.all(cordovaPlugins.map(async (p) => {
let allDependencies = []; let allDependencies = [];
allDependencies = allDependencies.concat((0, plugin_1.getPlatformElement)(p, platform, 'dependency')); allDependencies = allDependencies.concat((0, plugin_1.getPlatformElement)(p, platform, 'dependency'));
@ -431,8 +421,7 @@ async function checkPluginDependencies(plugins, platform) {
allDependencies = allDependencies.concat(p.xml['dependency']); allDependencies = allDependencies.concat(p.xml['dependency']);
} }
allDependencies = allDependencies.filter((dep) => !getIncompatibleCordovaPlugins(platform).includes(dep.$.id) && allDependencies = allDependencies.filter((dep) => !getIncompatibleCordovaPlugins(platform).includes(dep.$.id) &&
incompatible.filter(p => p.id === dep.$.id || p.xml.$.id === dep.$.id) incompatible.filter((p) => p.id === dep.$.id || p.xml.$.id === dep.$.id).length === 0);
.length === 0);
if (allDependencies) { if (allDependencies) {
await Promise.all(allDependencies.map(async (dep) => { await Promise.all(allDependencies.map(async (dep) => {
var _a; var _a;
@ -441,7 +430,7 @@ async function checkPluginDependencies(plugins, platform) {
if (plugin.includes('@') && plugin.indexOf('@') !== 0) { if (plugin.includes('@') && plugin.indexOf('@') !== 0) {
[plugin, version] = plugin.split('@'); [plugin, version] = plugin.split('@');
} }
if (cordovaPlugins.filter(p => p.id === plugin || p.xml.$.id === plugin).length === 0) { if (cordovaPlugins.filter((p) => p.id === plugin || p.xml.$.id === plugin).length === 0) {
if ((_a = dep.$.url) === null || _a === void 0 ? void 0 : _a.startsWith('http')) { if ((_a = dep.$.url) === null || _a === void 0 ? void 0 : _a.startsWith('http')) {
plugin = dep.$.url; plugin = dep.$.url;
version = dep.$.commit; version = dep.$.commit;
@ -457,9 +446,10 @@ async function checkPluginDependencies(plugins, platform) {
let msg = `${colors_1.default.failure(colors_1.default.strong('Plugins are missing dependencies.'))}\n` + let msg = `${colors_1.default.failure(colors_1.default.strong('Plugins are missing dependencies.'))}\n` +
`Cordova plugin dependencies must be installed in your project (e.g. w/ ${colors_1.default.input('npm install')}).\n`; `Cordova plugin dependencies must be installed in your project (e.g. w/ ${colors_1.default.input('npm install')}).\n`;
for (const [plugin, deps] of pluginDeps.entries()) { for (const [plugin, deps] of pluginDeps.entries()) {
msg += msg += `\n ${colors_1.default.strong(plugin)} is missing dependencies:\n` + deps.map((d) => ` - ${d}`).join('\n');
`\n ${colors_1.default.strong(plugin)} is missing dependencies:\n` + }
deps.map(d => ` - ${d}`).join('\n'); if (failOnMissingDeps) {
(0, errors_1.fatal)(`${msg}\n`);
} }
log_1.logger.warn(`${msg}\n`); log_1.logger.warn(`${msg}\n`);
} }
@ -490,18 +480,8 @@ function getIncompatibleCordovaPlugins(platform) {
return pluginList; return pluginList;
} }
exports.getIncompatibleCordovaPlugins = getIncompatibleCordovaPlugins; exports.getIncompatibleCordovaPlugins = getIncompatibleCordovaPlugins;
function needsStaticPod(plugin, config) { function needsStaticPod(plugin) {
var _a, _b, _c, _d; return useFrameworks(plugin);
let pluginList = [
'phonegap-plugin-push',
'@batch.com/cordova-plugin',
'onesignal-cordova-plugin',
];
if ((_b = (_a = config.app.extConfig) === null || _a === void 0 ? void 0 : _a.cordova) === null || _b === void 0 ? void 0 : _b.staticPlugins) {
log_1.logger.warn('cordova.staticPlugins is deprecated, make sure you are using latest version of the plugin');
pluginList = pluginList.concat((_d = (_c = config.app.extConfig) === null || _c === void 0 ? void 0 : _c.cordova) === null || _d === void 0 ? void 0 : _d.staticPlugins);
}
return pluginList.includes(plugin.id) || useFrameworks(plugin);
} }
exports.needsStaticPod = needsStaticPod; exports.needsStaticPod = needsStaticPod;
function useFrameworks(plugin) { function useFrameworks(plugin) {
@ -513,7 +493,7 @@ async function getCordovaPreferences(config) {
var _a, _b, _c, _d, _e; var _a, _b, _c, _d, _e;
const configXml = (0, path_1.join)(config.app.rootDir, 'config.xml'); const configXml = (0, path_1.join)(config.app.rootDir, 'config.xml');
let cordova = {}; let cordova = {};
if (await (0, utils_fs_1.pathExists)(configXml)) { if (await (0, fs_extra_1.pathExists)(configXml)) {
cordova.preferences = {}; cordova.preferences = {};
const xmlMeta = await (0, xml_1.readXML)(configXml); const xmlMeta = await (0, xml_1.readXML)(configXml);
if (xmlMeta.widget.preference) { if (xmlMeta.widget.preference) {
@ -573,16 +553,14 @@ async function writeCordovaAndroidManifest(cordovaPlugins, config, platform, cle
if (configElement.$ && if (configElement.$ &&
(((_a = configElement.$.target) === null || _a === void 0 ? void 0 : _a.includes('AndroidManifest.xml')) || (((_a = configElement.$.target) === null || _a === void 0 ? void 0 : _a.includes('AndroidManifest.xml')) ||
((_b = configElement.$.file) === null || _b === void 0 ? void 0 : _b.includes('AndroidManifest.xml')))) { ((_b = configElement.$.file) === null || _b === void 0 ? void 0 : _b.includes('AndroidManifest.xml')))) {
const keys = Object.keys(configElement).filter(k => k !== '$'); const keys = Object.keys(configElement).filter((k) => k !== '$');
keys.map(k => { keys.map((k) => {
configElement[k].map(async (e) => { configElement[k].map(async (e) => {
const xmlElement = (0, xml_1.buildXmlElement)(e, k); const xmlElement = (0, xml_1.buildXmlElement)(e, k);
const pathParts = getPathParts(configElement.$.parent || configElement.$.target); const pathParts = getPathParts(configElement.$.parent || configElement.$.target);
if (pathParts.length > 1) { if (pathParts.length > 1) {
if (pathParts.pop() === 'application') { if (pathParts.pop() === 'application') {
if (configElement.$.mode && if (configElement.$.mode && configElement.$.mode === 'merge' && xmlElement.startsWith('<application')) {
configElement.$.mode === 'merge' &&
xmlElement.startsWith('<application')) {
Object.keys(e.$).map((ek) => { Object.keys(e.$).map((ek) => {
applicationXMLAttributes.push(`${ek}="${e.$[ek]}"`); applicationXMLAttributes.push(`${ek}="${e.$[ek]}"`);
}); });
@ -594,7 +572,7 @@ async function writeCordovaAndroidManifest(cordovaPlugins, config, platform, cle
} }
else { else {
const manifestPathOfCapApp = (0, path_1.join)(config.android.appDirAbs, 'src', 'main', 'AndroidManifest.xml'); const manifestPathOfCapApp = (0, path_1.join)(config.android.appDirAbs, 'src', 'main', 'AndroidManifest.xml');
const manifestContentTrimmed = (await (0, utils_fs_1.readFile)(manifestPathOfCapApp)) const manifestContentTrimmed = (await (0, fs_extra_1.readFile)(manifestPathOfCapApp))
.toString() .toString()
.trim() .trim()
.replace(/\n|\t|\r/g, '') .replace(/\n|\t|\r/g, '')
@ -657,8 +635,7 @@ async function writeCordovaAndroidManifest(cordovaPlugins, config, platform, cle
if (requiredElement.name !== existingElement.name) { if (requiredElement.name !== existingElement.name) {
return false; return false;
} }
if ((requiredElement.attrs !== undefined) !== if ((requiredElement.attrs !== undefined) !== (existingElement.attrs !== undefined)) {
(existingElement.attrs !== undefined)) {
return false; return false;
} }
else { else {
@ -666,16 +643,14 @@ async function writeCordovaAndroidManifest(cordovaPlugins, config, platform, cle
const requiredELementAttrKeys = Object.keys(requiredElement.attrs); const requiredELementAttrKeys = Object.keys(requiredElement.attrs);
for (const key of requiredELementAttrKeys) { for (const key of requiredELementAttrKeys) {
if (!/^[$].{1,}$/.test(requiredElement.attrs[key].trim())) { if (!/^[$].{1,}$/.test(requiredElement.attrs[key].trim())) {
if (requiredElement.attrs[key] !== if (requiredElement.attrs[key] !== existingElement.attrs[key]) {
existingElement.attrs[key]) {
return false; return false;
} }
} }
} }
} }
} }
if ((requiredElement.children !== undefined) !== if ((requiredElement.children !== undefined) !== (existingElement.children !== undefined) &&
(existingElement.children !== undefined) &&
((_a = requiredElement.children) === null || _a === void 0 ? void 0 : _a.length) !== 0) { ((_a = requiredElement.children) === null || _a === void 0 ? void 0 : _a.length) !== 0) {
return false; return false;
} }
@ -697,8 +672,7 @@ async function writeCordovaAndroidManifest(cordovaPlugins, config, platform, cle
} }
} }
else { else {
if (requiredElement.children === undefined && if (requiredElement.children === undefined && existingElement.children === undefined) {
existingElement.children === undefined) {
return true; return true;
} }
else { else {
@ -736,8 +710,7 @@ async function writeCordovaAndroidManifest(cordovaPlugins, config, platform, cle
...requiredElements[rootKeyOfRequiredElements]['$'], ...requiredElements[rootKeyOfRequiredElements]['$'],
}; };
} }
if (requiredElements[rootKeyOfRequiredElements]['$$'] !== if (requiredElements[rootKeyOfRequiredElements]['$$'] !== undefined) {
undefined) {
parseXmlToSearchable(requiredElements[rootKeyOfRequiredElements]['$$'], rootOfRequiredElementsToAdd['children']); parseXmlToSearchable(requiredElements[rootKeyOfRequiredElements]['$$'], rootOfRequiredElementsToAdd['children']);
} }
parsedRequiredElements.push(rootOfRequiredElementsToAdd); parsedRequiredElements.push(rootOfRequiredElementsToAdd);
@ -771,8 +744,7 @@ async function writeCordovaAndroidManifest(cordovaPlugins, config, platform, cle
} }
} }
else { else {
if (!rootXMLEntries.includes(xmlElement) && if (!rootXMLEntries.includes(xmlElement) && !contains(rootXMLEntries, xmlElement, k)) {
!contains(rootXMLEntries, xmlElement, k)) {
rootXMLEntries.push(xmlElement); rootXMLEntries.push(xmlElement);
} }
} }
@ -782,8 +754,7 @@ async function writeCordovaAndroidManifest(cordovaPlugins, config, platform, cle
}); });
}); });
const cleartextString = 'android:usesCleartextTraffic="true"'; const cleartextString = 'android:usesCleartextTraffic="true"';
const cleartextValue = (cleartext || ((_a = config.app.extConfig.server) === null || _a === void 0 ? void 0 : _a.cleartext)) && const cleartextValue = (cleartext || ((_a = config.app.extConfig.server) === null || _a === void 0 ? void 0 : _a.cleartext)) && !applicationXMLAttributes.includes(cleartextString)
!applicationXMLAttributes.includes(cleartextString)
? cleartextString ? cleartextString
: ''; : '';
let content = `<?xml version='1.0' encoding='utf-8'?> let content = `<?xml version='1.0' encoding='utf-8'?>
@ -798,15 +769,15 @@ ${rootXMLEntries.join('\n')}
for (const preference of prefsArray) { for (const preference of prefsArray) {
content = content.replace(new RegExp(('$' + preference.$.name).replace('$', '\\$&'), 'g'), preference.$.default); content = content.replace(new RegExp(('$' + preference.$.name).replace('$', '\\$&'), 'g'), preference.$.default);
} }
if (await (0, utils_fs_1.pathExists)(manifestPath)) { if (await (0, fs_extra_1.pathExists)(manifestPath)) {
await (0, utils_fs_1.writeFile)(manifestPath, content); await (0, fs_extra_1.writeFile)(manifestPath, content);
} }
} }
exports.writeCordovaAndroidManifest = writeCordovaAndroidManifest; exports.writeCordovaAndroidManifest = writeCordovaAndroidManifest;
function getPathParts(path) { function getPathParts(path) {
const rootPath = 'manifest'; const rootPath = 'manifest';
path = path.replace('/*', rootPath); path = path.replace('/*', rootPath);
const parts = path.split('/').filter(part => part !== ''); const parts = path.split('/').filter((part) => part !== '');
if (parts.length > 1 || parts.includes(rootPath)) { if (parts.length > 1 || parts.includes(rootPath)) {
return parts; return parts;
} }

View file

@ -26,20 +26,6 @@ export interface CapacitorConfig {
* @since 1.0.0 * @since 1.0.0
*/ */
webDir?: string; webDir?: string;
/**
* Whether to copy the Capacitor runtime bundle or not.
*
* If your app is not using a bundler, set this to `true`, then Capacitor
* will create a `capacitor.js` file that you'll need to add as a script in
* your `index.html` file.
*
* It's deprecated and will be removed in Capacitor 6
*
* @since 1.0.0
* @deprecated 5.0.0
* @default false
*/
bundledWebRuntime?: boolean;
/** /**
* The build configuration (as defined by the native app) under which Capacitor * The build configuration (as defined by the native app) under which Capacitor
* will send statements to the log system. This applies to log statements in * will send statements to the log system. This applies to log statements in
@ -83,6 +69,13 @@ export interface CapacitorConfig {
* @since 6.0.0 * @since 6.0.0
*/ */
zoomEnabled?: boolean; zoomEnabled?: boolean;
/**
* Whether to give the webview initial focus.
*
* @since 7.0.0
* @default true
*/
initialFocus?: boolean;
android?: { android?: {
/** /**
* Specify a custom path to the native Android project. * Specify a custom path to the native Android project.
@ -186,6 +179,8 @@ export interface CapacitorConfig {
/** /**
* Whether to give the webview initial focus. * Whether to give the webview initial focus.
* *
* Overrides global `initialFocus` option.
*
* @since 3.5.1 * @since 3.5.1
* @default true * @default true
*/ */
@ -264,6 +259,24 @@ export interface CapacitorConfig {
* @default false * @default false
*/ */
useLegacyBridge?: boolean; useLegacyBridge?: boolean;
/**
* Make service worker requests go through Capacitor bridge.
* Set it to false to use your own handling.
*
* @since 7.0.0
* @default true
*/
resolveServiceWorkerRequests?: boolean;
/**
* If set to "force", margins will be adjusted for edge to edge regardless of any other settings.
* If set to "auto", or is missing, will check for Android 15 and the setting of [windowOptOutEdgeToEdgeEnforcement](https://developer.android.com/reference/android/R.attr#windowOptOutEdgeToEdgeEnforcement) and will adjust margins if on Android 15 and windowOptOutEdgeToEdgeEnforcement is false/missing.
* If set to "disable", will not adjust margins at all.
* In Capacitor 8, this default will be changed to 'auto'
*
* @since 7.1.0
* @default disable
*/
adjustMarginsForEdgeToEdge?: 'auto' | 'force' | 'disable';
}; };
ios?: { ios?: {
/** /**
@ -419,6 +432,43 @@ export interface CapacitorConfig {
* @default false * @default false
*/ */
webContentsDebuggingEnabled?: boolean; webContentsDebuggingEnabled?: boolean;
/**
* Whether to give the webview initial focus.
*
* Overrides global `initialFocus` option.
*
* @since 7.0.0
* @default true
*/
initialFocus?: boolean;
buildOptions?: {
/**
* The signing style to use when building the app for distribution.
*
* @since 7.1.0
* @default 'automatic'
*/
signingStyle?: 'automatic' | 'manual';
/**
* The method used by xcodebuild to export the archive
*
* @since 7.1.0
* @default 'app-store-connect'
*/
exportMethod?: string;
/**
* A certificate name, SHA-1 hash, or automatic selector to use for signing for iOS builds.
*
* @since 7.1.0
*/
signingCertificate?: string;
/**
* A provisioning profile name or UUID for iOS builds.
*
* @since 7.1.0
*/
provisioningProfile?: string;
};
}; };
server?: { server?: {
/** /**
@ -504,6 +554,14 @@ export interface CapacitorConfig {
* @default null * @default null
*/ */
errorPath?: string; errorPath?: string;
/**
* Append a path to the app URL.
*
* Allows loading from other paths than the default `/index.html`.
* @since 7.3.0
* @default null
*/
appStartPath?: string;
}; };
cordova?: { cordova?: {
/** /**
@ -524,15 +582,13 @@ export interface CapacitorConfig {
[key: string]: string | undefined; [key: string]: string | undefined;
}; };
/** /**
* List of Cordova plugins that need to be static but are not * Fail on cap update/sync if the CLI detects that a cordova plugin
* already in the static plugin list. * has uninstalled dependencies.
* *
* It's deprecated and will be removed in Capacitor 7 * @default false
* * @since 7.4.0
* @since 3.3.0
* @deprecated 6.1.1
*/ */
staticPlugins?: string[]; failOnUninstalledPlugins?: boolean;
}; };
/** /**
* Configure plugins. * Configure plugins.

View file

@ -1,2 +1,13 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.XcodeExportMethod = void 0;
var XcodeExportMethod;
(function (XcodeExportMethod) {
XcodeExportMethod["AppStoreConnect"] = "app-store-connect";
XcodeExportMethod["ReleaseTesting"] = "release-testing";
XcodeExportMethod["Enterprise"] = "enterprise";
XcodeExportMethod["Debugging"] = "debugging";
XcodeExportMethod["DeveloperID"] = "developer-id";
XcodeExportMethod["MacApplication"] = "mac-application";
XcodeExportMethod["Validation"] = "validation";
})(XcodeExportMethod = exports.XcodeExportMethod || (exports.XcodeExportMethod = {}));

View file

@ -4,85 +4,85 @@ exports.detectFramework = void 0;
const FRAMEWORK_CONFIGS = [ const FRAMEWORK_CONFIGS = [
{ {
name: 'Angular', name: 'Angular',
isMatch: config => hasDependency(config, '@angular/cli'), isMatch: (config) => hasDependency(config, '@angular/cli'),
webDir: 'dist', webDir: 'dist',
priority: 3, priority: 3,
}, },
{ {
name: 'Create React App', name: 'Create React App',
isMatch: config => hasDependency(config, 'react-scripts'), isMatch: (config) => hasDependency(config, 'react-scripts'),
webDir: 'build', webDir: 'build',
priority: 3, priority: 3,
}, },
{ {
name: 'Ember', name: 'Ember',
isMatch: config => hasDependency(config, 'ember-cli'), isMatch: (config) => hasDependency(config, 'ember-cli'),
webDir: 'dist', webDir: 'dist',
priority: 3, priority: 3,
}, },
{ {
name: 'Gatsby', name: 'Gatsby',
isMatch: config => hasDependency(config, 'gatsby'), isMatch: (config) => hasDependency(config, 'gatsby'),
webDir: 'public', webDir: 'public',
priority: 2, priority: 2,
}, },
{ {
name: 'Ionic Angular', name: 'Ionic Angular',
isMatch: config => hasDependency(config, '@ionic/angular'), isMatch: (config) => hasDependency(config, '@ionic/angular'),
webDir: 'www', webDir: 'www',
priority: 1, priority: 1,
}, },
{ {
name: 'Ionic React', name: 'Ionic React',
isMatch: config => hasDependency(config, '@ionic/react'), isMatch: (config) => hasDependency(config, '@ionic/react'),
webDir: 'build', webDir: 'build',
priority: 1, priority: 1,
}, },
{ {
name: 'Ionic Vue', name: 'Ionic Vue',
isMatch: config => hasDependency(config, '@ionic/vue'), isMatch: (config) => hasDependency(config, '@ionic/vue'),
webDir: 'public', webDir: 'public',
priority: 1, priority: 1,
}, },
{ {
name: 'Next', name: 'Next',
isMatch: config => hasDependency(config, 'next'), isMatch: (config) => hasDependency(config, 'next'),
webDir: 'public', webDir: 'public',
priority: 2, priority: 2,
}, },
{ {
name: 'Preact', name: 'Preact',
isMatch: config => hasDependency(config, 'preact-cli'), isMatch: (config) => hasDependency(config, 'preact-cli'),
webDir: 'build', webDir: 'build',
priority: 3, priority: 3,
}, },
{ {
name: 'Stencil', name: 'Stencil',
isMatch: config => hasDependency(config, '@stencil/core'), isMatch: (config) => hasDependency(config, '@stencil/core'),
webDir: 'www', webDir: 'www',
priority: 3, priority: 3,
}, },
{ {
name: 'Svelte', name: 'Svelte',
isMatch: config => hasDependency(config, 'svelte') && hasDependency(config, 'sirv-cli'), isMatch: (config) => hasDependency(config, 'svelte') && hasDependency(config, 'sirv-cli'),
webDir: 'public', webDir: 'public',
priority: 3, priority: 3,
}, },
{ {
name: 'Vite', name: 'Vite',
isMatch: config => hasDependency(config, 'vite'), isMatch: (config) => hasDependency(config, 'vite'),
webDir: 'dist', webDir: 'dist',
priority: 2, priority: 2,
}, },
{ {
name: 'Vue', name: 'Vue',
isMatch: config => hasDependency(config, '@vue/cli-service'), isMatch: (config) => hasDependency(config, '@vue/cli-service'),
webDir: 'dist', webDir: 'dist',
priority: 3, priority: 3,
}, },
]; ];
function detectFramework(config) { function detectFramework(config) {
const frameworks = FRAMEWORK_CONFIGS.filter(f => f.isMatch(config)).sort((a, b) => { const frameworks = FRAMEWORK_CONFIGS.filter((f) => f.isMatch(config)).sort((a, b) => {
if (a.priority < b.priority) if (a.priority < b.priority)
return -1; return -1;
if (a.priority > b.priority) if (a.priority > b.priority)

View file

@ -12,7 +12,7 @@ const log_1 = require("./log");
const telemetry_1 = require("./telemetry"); const telemetry_1 = require("./telemetry");
const cli_1 = require("./util/cli"); const cli_1 = require("./util/cli");
const emoji_1 = require("./util/emoji"); const emoji_1 = require("./util/emoji");
process.on('unhandledRejection', error => { process.on('unhandledRejection', (error) => {
console.error(colors_1.default.failure('[fatal]'), error); console.error(colors_1.default.failure('[fatal]'), error);
}); });
process.on('message', ipc_1.receive); process.on('message', ipc_1.receive);
@ -48,9 +48,10 @@ function runProgram(config) {
.command('init [appName] [appId]') .command('init [appName] [appId]')
.description(`Initialize Capacitor configuration`) .description(`Initialize Capacitor configuration`)
.option('--web-dir <value>', 'Optional: Directory of your projects built web assets') .option('--web-dir <value>', 'Optional: Directory of your projects built web assets')
.action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (appName, appId, { webDir }) => { .option('--skip-appid-validation', 'Optional: Skip validating the app ID for iOS and Android compatibility')
.action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (appName, appId, { webDir, skipAppidValidation }) => {
const { initCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/init'))); const { initCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/init')));
await initCommand(config, appName, appId, webDir); await initCommand(config, appName, appId, webDir, skipAppidValidation);
}))); })));
commander_1.program commander_1.program
.command('serve', { hidden: true }) .command('serve', { hidden: true })
@ -65,7 +66,6 @@ function runProgram(config) {
.option('--deployment', 'Optional: if provided, pod install will use --deployment option') .option('--deployment', 'Optional: if provided, pod install will use --deployment option')
.option('--inline', 'Optional: if true, all source maps will be inlined for easier debugging on mobile devices', false) .option('--inline', 'Optional: if true, all source maps will be inlined for easier debugging on mobile devices', false)
.action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform, { deployment, inline }) => { .action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform, { deployment, inline }) => {
(0, config_1.checkExternalConfig)(config.app);
const { syncCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/sync'))); const { syncCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/sync')));
await syncCommand(config, platform, deployment, inline); await syncCommand(config, platform, deployment, inline);
}))); })));
@ -74,7 +74,6 @@ function runProgram(config) {
.description(`updates the native plugins and dependencies based on ${colors_1.default.strong('package.json')}`) .description(`updates the native plugins and dependencies based on ${colors_1.default.strong('package.json')}`)
.option('--deployment', 'Optional: if provided, pod install will use --deployment option') .option('--deployment', 'Optional: if provided, pod install will use --deployment option')
.action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform, { deployment }) => { .action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform, { deployment }) => {
(0, config_1.checkExternalConfig)(config.app);
const { updateCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/update'))); const { updateCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/update')));
await updateCommand(config, platform, deployment); await updateCommand(config, platform, deployment);
}))); })));
@ -83,7 +82,6 @@ function runProgram(config) {
.description('copies the web app build into the native app') .description('copies the web app build into the native app')
.option('--inline', 'Optional: if true, all source maps will be inlined for easier debugging on mobile devices', false) .option('--inline', 'Optional: if true, all source maps will be inlined for easier debugging on mobile devices', false)
.action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform, { inline }) => { .action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform, { inline }) => {
(0, config_1.checkExternalConfig)(config.app);
const { copyCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/copy'))); const { copyCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/copy')));
await copyCommand(config, platform, inline); await copyCommand(config, platform, inline);
}))); })));
@ -97,9 +95,28 @@ function runProgram(config) {
.option('--keystorealias <keystoreAlias>', 'Key Alias in the keystore') .option('--keystorealias <keystoreAlias>', 'Key Alias in the keystore')
.option('--configuration <name>', 'Configuration name of the iOS Scheme') .option('--configuration <name>', 'Configuration name of the iOS Scheme')
.option('--keystorealiaspass <keystoreAliasPass>', 'Password for the Key Alias') .option('--keystorealiaspass <keystoreAliasPass>', 'Password for the Key Alias')
.addOption(new commander_1.Option('--androidreleasetype <androidreleasetype>', 'Android release type; APK or AAB').choices(['AAB', 'APK'])) .addOption(new commander_1.Option('--androidreleasetype <androidreleasetype>', 'Android release type; APK or AAB').choices([
.addOption(new commander_1.Option('--signing-type <signingtype>', 'Program used to sign apps (default: jarsigner)').choices(['apksigner', 'jarsigner'])) 'AAB',
.action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform, { scheme, flavor, keystorepath, keystorepass, keystorealias, keystorealiaspass, androidreleasetype, signingType, configuration, }) => { 'APK',
]))
.addOption(new commander_1.Option('--signing-type <signingtype>', 'Program used to sign apps (default: jarsigner)').choices([
'apksigner',
'jarsigner',
]))
.addOption(new commander_1.Option('--xcode-team-id <xcodeTeamID>', 'The Developer team to use for building and exporting the archive'))
.addOption(new commander_1.Option('--xcode-export-method <xcodeExportMethod>', 'Describes how xcodebuild should export the archive (default: app-store-connect)').choices([
'app-store-connect',
'release-testing',
'enterprise',
'debugging',
'developer-id',
'mac-application',
'validation',
]))
.addOption(new commander_1.Option('--xcode-signing-style <xcodeSigningStyle>', 'The iOS signing style to use when building the app for distribution (default: automatic)').choices(['automatic', 'manual']))
.addOption(new commander_1.Option('--xcode-signing-certificate <xcodeSigningCertificate>', 'A certificate name, SHA-1 hash, or automatic selector to use for signing for iOS builds'))
.addOption(new commander_1.Option('--xcode-provisioning-profile <xcodeProvisioningProfile>', 'A provisioning profile name or UUID for iOS builds'))
.action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform, { scheme, flavor, keystorepath, keystorepass, keystorealias, keystorealiaspass, androidreleasetype, signingType, configuration, xcodeTeamId, xcodeExportMethod, xcodeSigningStyle, xcodeSigningCertificate, xcodeProvisioningProfile, }) => {
const { buildCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/build'))); const { buildCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/build')));
await buildCommand(config, platform, { await buildCommand(config, platform, {
scheme, scheme,
@ -111,6 +128,11 @@ function runProgram(config) {
androidreleasetype, androidreleasetype,
signingtype: signingType, signingtype: signingType,
configuration, configuration,
xcodeTeamId,
xcodeExportMethod,
xcodeSigningType: xcodeSigningStyle,
xcodeSigningCertificate,
xcodeProvisioningProfile,
}); });
}))); })));
commander_1.program commander_1.program
@ -119,8 +141,7 @@ function runProgram(config) {
.option('--scheme <schemeName>', 'set the scheme of the iOS project') .option('--scheme <schemeName>', 'set the scheme of the iOS project')
.option('--flavor <flavorName>', 'set the flavor of the Android project (flavor dimensions not yet supported)') .option('--flavor <flavorName>', 'set the flavor of the Android project (flavor dimensions not yet supported)')
.option('--list', 'list targets, then quit') .option('--list', 'list targets, then quit')
// TODO: remove once --json is a hidden option (https://github.com/tj/commander.js/issues/1106) .addOption(new commander_1.Option('--json').hideHelp())
.allowUnknownOption(true)
.option('--target <id>', 'use a specific target') .option('--target <id>', 'use a specific target')
.option('--no-sync', `do not run ${colors_1.default.input('sync')}`) .option('--no-sync', `do not run ${colors_1.default.input('sync')}`)
.option('--forwardPorts <port:port>', 'Automatically run "adb reverse" for better live-reloading support') .option('--forwardPorts <port:port>', 'Automatically run "adb reverse" for better live-reloading support')
@ -128,12 +149,13 @@ function runProgram(config) {
.option('--host <host>', 'Host used for live reload') .option('--host <host>', 'Host used for live reload')
.option('--port <port>', 'Port used for live reload') .option('--port <port>', 'Port used for live reload')
.option('--configuration <name>', 'Configuration name of the iOS Scheme') .option('--configuration <name>', 'Configuration name of the iOS Scheme')
.action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform, { scheme, flavor, list, target, sync, forwardPorts, liveReload, host, port, configuration, }) => { .action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform, { scheme, flavor, list, json, target, sync, forwardPorts, liveReload, host, port, configuration }) => {
const { runCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/run'))); const { runCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/run')));
await runCommand(config, platform, { await runCommand(config, platform, {
scheme, scheme,
flavor, flavor,
list, list,
json,
target, target,
sync, sync,
forwardPorts, forwardPorts,
@ -153,14 +175,12 @@ function runProgram(config) {
commander_1.program commander_1.program
.command('add [platform]') .command('add [platform]')
.description('add a native platform project') .description('add a native platform project')
.option('--packagemanager <packageManager>', 'The package manager to use for dependency installs (Cocoapods, SPM **experimental**)') .option('--packagemanager <packageManager>', 'The package manager to use for dependency installs (CocoaPods or SPM)')
.action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform, { packagemanager }) => { .action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform, { packagemanager }) => {
(0, config_1.checkExternalConfig)(config.app);
const { addCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/add'))); const { addCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/add')));
const configWritable = config; const configWritable = config;
if (packagemanager === 'SPM') { if (packagemanager === 'SPM') {
configWritable.cli.assets.ios.platformTemplateArchive = configWritable.cli.assets.ios.platformTemplateArchive = 'ios-spm-template.tar.gz';
'ios-spm-template.tar.gz';
configWritable.cli.assets.ios.platformTemplateArchiveAbs = (0, path_1.resolve)(configWritable.cli.assetsDirAbs, configWritable.cli.assets.ios.platformTemplateArchive); configWritable.cli.assets.ios.platformTemplateArchiveAbs = (0, path_1.resolve)(configWritable.cli.assetsDirAbs, configWritable.cli.assets.ios.platformTemplateArchive);
} }
await addCommand(configWritable, platform); await addCommand(configWritable, platform);
@ -169,7 +189,6 @@ function runProgram(config) {
.command('ls [platform]') .command('ls [platform]')
.description('list installed Cordova and Capacitor plugins') .description('list installed Cordova and Capacitor plugins')
.action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform) => { .action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform) => {
(0, config_1.checkExternalConfig)(config.app);
const { listCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/list'))); const { listCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/list')));
await listCommand(config, platform); await listCommand(config, platform);
}))); })));
@ -177,7 +196,6 @@ function runProgram(config) {
.command('doctor [platform]') .command('doctor [platform]')
.description('checks the current setup for common errors') .description('checks the current setup for common errors')
.action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform) => { .action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform) => {
(0, config_1.checkExternalConfig)(config.app);
const { doctorCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/doctor'))); const { doctorCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/doctor')));
await doctorCommand(config, platform); await doctorCommand(config, platform);
}))); })));
@ -210,6 +228,13 @@ function runProgram(config) {
const { migrateCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/migrate'))); const { migrateCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/migrate')));
await migrateCommand(config, noprompt, packagemanager); await migrateCommand(config, noprompt, packagemanager);
})); }));
commander_1.program
.command('spm-migration-assistant')
.description('Remove Cocoapods from project and switch to Swift Package Manager')
.action((0, cli_1.wrapAction)(async () => {
const { migrateToSPM } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/migrate-spm')));
await migrateToSPM(config);
}));
commander_1.program.arguments('[command]').action((0, cli_1.wrapAction)(async (cmd) => { commander_1.program.arguments('[command]').action((0, cli_1.wrapAction)(async (cmd) => {
if (typeof cmd === 'undefined') { if (typeof cmd === 'undefined') {
log_1.output.write(`\n ${(0, emoji_1.emoji)('⚡️', '--')} ${colors_1.default.strong('Capacitor - Cross-Platform apps with JavaScript and the Web')} ${(0, emoji_1.emoji)('⚡️', '--')}\n\n`); log_1.output.write(`\n ${(0, emoji_1.emoji)('⚡️', '--')} ${colors_1.default.strong('Capacitor - Cross-Platform apps with JavaScript and the Web')} ${(0, emoji_1.emoji)('⚡️', '--')}\n\n`);

View file

@ -1,16 +1,16 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.buildiOS = void 0; exports.buildiOS = void 0;
const tslib_1 = require("tslib"); const fs_extra_1 = require("fs-extra");
const utils_fs_1 = require("@ionic/utils-fs");
const path_1 = require("path"); const path_1 = require("path");
const rimraf_1 = tslib_1.__importDefault(require("rimraf")); const rimraf_1 = require("rimraf");
const common_1 = require("../common"); const common_1 = require("../common");
const definitions_1 = require("../definitions");
const log_1 = require("../log"); const log_1 = require("../log");
const spm_1 = require("../util/spm"); const spm_1 = require("../util/spm");
const subprocess_1 = require("../util/subprocess"); const subprocess_1 = require("../util/subprocess");
async function buildiOS(config, buildOptions) { async function buildiOS(config, buildOptions) {
var _a; var _a, _b, _c, _d;
const theScheme = (_a = buildOptions.scheme) !== null && _a !== void 0 ? _a : 'App'; const theScheme = (_a = buildOptions.scheme) !== null && _a !== void 0 ? _a : 'App';
const packageManager = await (0, spm_1.checkPackageManager)(config); const packageManager = await (0, spm_1.checkPackageManager)(config);
let typeOfBuild; let typeOfBuild;
@ -23,7 +23,11 @@ async function buildiOS(config, buildOptions) {
typeOfBuild = '-project'; typeOfBuild = '-project';
projectName = (0, path_1.basename)(await config.ios.nativeXcodeProjDirAbs); projectName = (0, path_1.basename)(await config.ios.nativeXcodeProjDirAbs);
} }
await (0, common_1.runTask)('Building xArchive', async () => (0, subprocess_1.runCommand)('xcodebuild', [ if (buildOptions.xcodeSigningType == 'manual' &&
(!buildOptions.xcodeSigningCertificate || !buildOptions.xcodeProvisioningProfile)) {
throw 'Manually signed Xcode builds require a signing certificate and provisioning profile.';
}
const buildArgs = [
typeOfBuild, typeOfBuild,
projectName, projectName,
'-scheme', '-scheme',
@ -33,20 +37,39 @@ async function buildiOS(config, buildOptions) {
'-archivePath', '-archivePath',
`${theScheme}.xcarchive`, `${theScheme}.xcarchive`,
'archive', 'archive',
], { '-configuration',
buildOptions.configuration,
];
if (buildOptions.xcodeTeamId) {
buildArgs.push(`DEVELOPMENT_TEAM=${buildOptions.xcodeTeamId}`);
}
if (buildOptions.xcodeSigningType == 'manual') {
buildArgs.push(`PROVISIONING_PROFILE_SPECIFIER=${buildOptions.xcodeProvisioningProfile}`);
}
await (0, common_1.runTask)('Building xArchive', async () => (0, subprocess_1.runCommand)('xcodebuild', buildArgs, {
cwd: config.ios.nativeProjectDirAbs, cwd: config.ios.nativeProjectDirAbs,
})); }));
const manualSigningContents = `<key>provisioningProfiles</key>
<dict>
<key>${config.app.appId}</key>
<string>${(_b = buildOptions.xcodeProvisioningProfile) !== null && _b !== void 0 ? _b : ''}</string>
</dict>
<key>signingCertificate</key>
<string>${(_c = buildOptions.xcodeSigningCertificate) !== null && _c !== void 0 ? _c : ''}</string>`;
const archivePlistContents = `<?xml version="1.0" encoding="UTF-8"?> const archivePlistContents = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>method</key> <key>method</key>
<string>app-store</string> <string>${(_d = buildOptions.xcodeExportMethod) !== null && _d !== void 0 ? _d : definitions_1.XcodeExportMethod.AppStoreConnect}</string>
<key>signingStyle</key>
<string>${buildOptions.xcodeSigningType}</string>
${buildOptions.xcodeSigningType == 'manual' ? manualSigningContents : ''}
</dict> </dict>
</plist>`; </plist>`;
const archivePlistPath = (0, path_1.join)(`${config.ios.nativeProjectDirAbs}`, 'archive.plist'); const archivePlistPath = (0, path_1.join)(`${config.ios.nativeProjectDirAbs}`, 'archive.plist');
(0, utils_fs_1.writeFileSync)(archivePlistPath, archivePlistContents); (0, fs_extra_1.writeFileSync)(archivePlistPath, archivePlistContents);
await (0, common_1.runTask)('Building IPA', async () => (0, subprocess_1.runCommand)('xcodebuild', [ const archiveArgs = [
'archive', 'archive',
'-archivePath', '-archivePath',
`${theScheme}.xcarchive`, `${theScheme}.xcarchive`,
@ -55,15 +78,18 @@ async function buildiOS(config, buildOptions) {
'archive.plist', 'archive.plist',
'-exportPath', '-exportPath',
'output', 'output',
'-allowProvisioningUpdates',
'-configuration', '-configuration',
buildOptions.configuration, buildOptions.configuration,
], { ];
if (buildOptions.xcodeSigningType == 'automatic') {
archiveArgs.push('-allowProvisioningUpdates');
}
await (0, common_1.runTask)('Building IPA', async () => (0, subprocess_1.runCommand)('xcodebuild', archiveArgs, {
cwd: config.ios.nativeProjectDirAbs, cwd: config.ios.nativeProjectDirAbs,
})); }));
await (0, common_1.runTask)('Cleaning up', async () => { await (0, common_1.runTask)('Cleaning up', async () => {
(0, utils_fs_1.unlinkSync)(archivePlistPath); (0, fs_extra_1.unlinkSync)(archivePlistPath);
rimraf_1.default.sync((0, path_1.join)(config.ios.nativeProjectDirAbs, `${theScheme}.xcarchive`)); rimraf_1.rimraf.sync((0, path_1.join)(config.ios.nativeProjectDirAbs, `${theScheme}.xcarchive`));
}); });
(0, log_1.logSuccess)(`Successfully generated an IPA at: ${(0, path_1.join)(config.ios.nativeProjectDirAbs, 'output')}`); (0, log_1.logSuccess)(`Successfully generated an IPA at: ${(0, path_1.join)(config.ios.nativeProjectDirAbs, 'output')}`);
} }

View file

@ -1,9 +1,9 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.editProjectSettingsIOS = exports.resolvePlugin = exports.getIOSPlugins = exports.checkCocoaPods = exports.checkBundler = exports.checkIOSPackage = void 0; exports.getMajoriOSVersion = exports.editProjectSettingsIOS = exports.resolvePlugin = exports.getIOSPlugins = exports.checkCocoaPods = exports.checkBundler = exports.checkIOSPackage = void 0;
const tslib_1 = require("tslib"); const tslib_1 = require("tslib");
const utils_fs_1 = require("@ionic/utils-fs");
const child_process_1 = require("child_process"); const child_process_1 = require("child_process");
const fs_extra_1 = require("fs-extra");
const path_1 = require("path"); const path_1 = require("path");
const colors_1 = tslib_1.__importDefault(require("../colors")); const colors_1 = tslib_1.__importDefault(require("../colors"));
const common_1 = require("../common"); const common_1 = require("../common");
@ -42,8 +42,7 @@ async function checkBundler(config) {
} }
exports.checkBundler = checkBundler; exports.checkBundler = checkBundler;
async function checkCocoaPods(config) { async function checkCocoaPods(config) {
if (!(await (0, subprocess_1.isInstalled)(await config.ios.podPath)) && if (!(await (0, subprocess_1.isInstalled)(await config.ios.podPath)) && config.cli.os === "mac" /* OS.Mac */) {
config.cli.os === "mac" /* OS.Mac */) {
return (`CocoaPods is not installed.\n` + return (`CocoaPods is not installed.\n` +
`See this install guide: ${colors_1.default.strong('https://capacitorjs.com/docs/getting-started/environment-setup#homebrew')}`); `See this install guide: ${colors_1.default.strong('https://capacitorjs.com/docs/getting-started/environment-setup#homebrew')}`);
} }
@ -71,8 +70,7 @@ async function resolvePlugin(plugin) {
type: 1 /* PluginType.Cordova */, type: 1 /* PluginType.Cordova */,
path: 'src/' + platform, path: 'src/' + platform,
}; };
if ((0, cordova_1.getIncompatibleCordovaPlugins)(platform).includes(plugin.id) || if ((0, cordova_1.getIncompatibleCordovaPlugins)(platform).includes(plugin.id) || !(0, plugin_1.getPluginPlatform)(plugin, platform)) {
!(0, plugin_1.getPluginPlatform)(plugin, platform)) {
plugin.ios.type = 2 /* PluginType.Incompatible */; plugin.ios.type = 2 /* PluginType.Incompatible */;
} }
} }
@ -87,17 +85,21 @@ exports.resolvePlugin = resolvePlugin;
*/ */
async function editProjectSettingsIOS(config) { async function editProjectSettingsIOS(config) {
const appId = config.app.appId; const appId = config.app.appId;
const appName = config.app.appName const appName = config.app.appName.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
const pbxPath = `${config.ios.nativeXcodeProjDirAbs}/project.pbxproj`; const pbxPath = `${config.ios.nativeXcodeProjDirAbs}/project.pbxproj`;
const plistPath = (0, path_1.resolve)(config.ios.nativeTargetDirAbs, 'Info.plist'); const plistPath = (0, path_1.resolve)(config.ios.nativeTargetDirAbs, 'Info.plist');
let plistContent = await (0, utils_fs_1.readFile)(plistPath, { encoding: 'utf-8' }); let plistContent = await (0, fs_extra_1.readFile)(plistPath, { encoding: 'utf-8' });
plistContent = plistContent.replace(/<key>CFBundleDisplayName<\/key>[\s\S]?\s+<string>([^<]*)<\/string>/, `<key>CFBundleDisplayName</key>\n <string>${appName}</string>`); plistContent = plistContent.replace(/<key>CFBundleDisplayName<\/key>[\s\S]?\s+<string>([^<]*)<\/string>/, `<key>CFBundleDisplayName</key>\n <string>${appName}</string>`);
let pbxContent = await (0, utils_fs_1.readFile)(pbxPath, { encoding: 'utf-8' }); let pbxContent = await (0, fs_extra_1.readFile)(pbxPath, { encoding: 'utf-8' });
pbxContent = pbxContent.replace(/PRODUCT_BUNDLE_IDENTIFIER = ([^;]+)/g, `PRODUCT_BUNDLE_IDENTIFIER = ${appId}`); pbxContent = pbxContent.replace(/PRODUCT_BUNDLE_IDENTIFIER = ([^;]+)/g, `PRODUCT_BUNDLE_IDENTIFIER = ${appId}`);
await (0, utils_fs_1.writeFile)(plistPath, plistContent, { encoding: 'utf-8' }); await (0, fs_extra_1.writeFile)(plistPath, plistContent, { encoding: 'utf-8' });
await (0, utils_fs_1.writeFile)(pbxPath, pbxContent, { encoding: 'utf-8' }); await (0, fs_extra_1.writeFile)(pbxPath, pbxContent, { encoding: 'utf-8' });
} }
exports.editProjectSettingsIOS = editProjectSettingsIOS; exports.editProjectSettingsIOS = editProjectSettingsIOS;
function getMajoriOSVersion(config) {
const pbx = (0, fs_extra_1.readFileSync)((0, path_1.join)(config.ios.nativeXcodeProjDirAbs, 'project.pbxproj'), 'utf-8');
const searchString = 'IPHONEOS_DEPLOYMENT_TARGET = ';
const iosVersion = pbx.substring(pbx.indexOf(searchString) + searchString.length, pbx.indexOf(searchString) + searchString.length + 2);
return iosVersion;
}
exports.getMajoriOSVersion = getMajoriOSVersion;

View file

@ -20,11 +20,7 @@ async function doctorIOS(config) {
// check online datebase of common errors // check online datebase of common errors
// check if www folder is empty (index.html does not exist) // check if www folder is empty (index.html does not exist)
try { try {
await (0, common_1.check)([ await (0, common_1.check)([() => (0, common_2.checkBundler)(config) || (0, common_2.checkCocoaPods)(config), () => (0, common_1.checkWebDir)(config), checkXcode]);
() => (0, common_2.checkBundler)(config) || (0, common_2.checkCocoaPods)(config),
() => (0, common_1.checkWebDir)(config),
checkXcode,
]);
(0, log_1.logSuccess)('iOS looking great! 👌'); (0, log_1.logSuccess)('iOS looking great! 👌');
} }
catch (e) { catch (e) {

View file

@ -10,7 +10,7 @@ const native_run_1 = require("../util/native-run");
const spm_1 = require("../util/spm"); const spm_1 = require("../util/spm");
const subprocess_1 = require("../util/subprocess"); const subprocess_1 = require("../util/subprocess");
const debug = (0, debug_1.default)('capacitor:ios:run'); const debug = (0, debug_1.default)('capacitor:ios:run');
async function runIOS(config, { target: selectedTarget, scheme: selectedScheme, configuration: selectedConfiguration, }) { async function runIOS(config, { target: selectedTarget, scheme: selectedScheme, configuration: selectedConfiguration }) {
const target = await (0, common_1.promptForPlatformTarget)(await (0, native_run_1.getPlatformTargets)('ios'), selectedTarget); const target = await (0, common_1.promptForPlatformTarget)(await (0, native_run_1.getPlatformTargets)('ios'), selectedTarget);
const runScheme = selectedScheme || config.ios.scheme; const runScheme = selectedScheme || config.ios.scheme;
const configuration = selectedConfiguration || 'Debug'; const configuration = selectedConfiguration || 'Debug';
@ -43,9 +43,7 @@ async function runIOS(config, { target: selectedTarget, scheme: selectedScheme,
cwd: config.ios.nativeProjectDirAbs, cwd: config.ios.nativeProjectDirAbs,
})); }));
const appName = `${runScheme}.app`; const appName = `${runScheme}.app`;
const appPath = (0, path_1.resolve)(derivedDataPath, 'Build/Products', target.virtual const appPath = (0, path_1.resolve)(derivedDataPath, 'Build/Products', target.virtual ? `${configuration}-iphonesimulator` : `${configuration}-iphoneos`, appName);
? `${configuration}-iphonesimulator`
: `${configuration}-iphoneos`, appName);
const nativeRunArgs = ['ios', '--app', appPath, '--target', target.id]; const nativeRunArgs = ['ios', '--app', appPath, '--target', target.id];
debug('Invoking native-run with args: %O', nativeRunArgs); debug('Invoking native-run with args: %O', nativeRunArgs);
await (0, common_1.runTask)(`Deploying ${colors_1.default.strong(appName)} to ${colors_1.default.input(target.id)}`, async () => (0, native_run_1.runNativeRun)(nativeRunArgs)); await (0, common_1.runTask)(`Deploying ${colors_1.default.strong(appName)} to ${colors_1.default.input(target.id)}`, async () => (0, native_run_1.runNativeRun)(nativeRunArgs));

View file

@ -2,7 +2,7 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.installCocoaPodsPlugins = exports.updateIOS = void 0; exports.installCocoaPodsPlugins = exports.updateIOS = void 0;
const tslib_1 = require("tslib"); const tslib_1 = require("tslib");
const utils_fs_1 = require("@ionic/utils-fs"); const fs_extra_1 = require("fs-extra");
const path_1 = require("path"); const path_1 = require("path");
const colors_1 = tslib_1.__importDefault(require("../colors")); const colors_1 = tslib_1.__importDefault(require("../colors"));
const common_1 = require("../common"); const common_1 = require("../common");
@ -21,34 +21,79 @@ const common_2 = require("./common");
const platform = 'ios'; const platform = 'ios';
async function updateIOS(config, deployment) { async function updateIOS(config, deployment) {
const plugins = await getPluginsTask(config); const plugins = await getPluginsTask(config);
const capacitorPlugins = plugins.filter(p => (0, plugin_1.getPluginType)(p, platform) === 0 /* PluginType.Core */); const capacitorPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 0 /* PluginType.Core */);
if ((await (0, spm_1.checkPackageManager)(config)) === 'SPM') { await updatePluginFiles(config, plugins, deployment);
await (0, spm_1.generatePackageFile)(config, capacitorPlugins); await (0, common_1.checkPlatformVersions)(config, platform);
}
else {
await updateIOSCocoaPods(config, plugins, deployment);
}
(0, iosplugin_1.generateIOSPackageJSON)(config, plugins); (0, iosplugin_1.generateIOSPackageJSON)(config, plugins);
(0, plugin_1.printPlugins)(capacitorPlugins, 'ios'); (0, plugin_1.printPlugins)(capacitorPlugins, 'ios');
} }
exports.updateIOS = updateIOS; exports.updateIOS = updateIOS;
async function updateIOSCocoaPods(config, plugins, deployment) { async function updatePluginFiles(config, plugins, deployment) {
var _a;
await removePluginsNativeFiles(config); await removePluginsNativeFiles(config);
const cordovaPlugins = plugins.filter(p => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */); const cordovaPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */);
if (cordovaPlugins.length > 0) { if (cordovaPlugins.length > 0) {
await copyPluginsNativeFiles(config, cordovaPlugins); await copyPluginsNativeFiles(config, cordovaPlugins);
} }
if (!(await (0, utils_fs_1.pathExists)(await config.ios.webDirAbs))) { if (!(await (0, fs_extra_1.pathExists)(await config.ios.webDirAbs))) {
await (0, copy_1.copy)(config, platform); await (0, copy_1.copy)(config, platform);
} }
await (0, cordova_1.handleCordovaPluginsJS)(cordovaPlugins, config, platform); await (0, cordova_1.handleCordovaPluginsJS)(cordovaPlugins, config, platform);
await (0, cordova_1.checkPluginDependencies)(plugins, platform); await (0, cordova_1.checkPluginDependencies)(plugins, platform, (_a = config.app.extConfig.cordova) === null || _a === void 0 ? void 0 : _a.failOnUninstalledPlugins);
await generateCordovaPodspecs(cordovaPlugins, config); if ((await (0, spm_1.checkPackageManager)(config)) === 'SPM') {
await installCocoaPodsPlugins(config, plugins, deployment); await generateCordovaPackageFiles(cordovaPlugins, config);
const validSPMPackages = await (0, spm_1.checkPluginsForPackageSwift)(config, plugins);
await (0, spm_1.generatePackageFile)(config, validSPMPackages);
}
else {
await generateCordovaPodspecs(cordovaPlugins, config);
await installCocoaPodsPlugins(config, plugins, deployment);
}
await (0, cordova_1.logCordovaManualSteps)(cordovaPlugins, config, platform); await (0, cordova_1.logCordovaManualSteps)(cordovaPlugins, config, platform);
const incompatibleCordovaPlugins = plugins.filter(p => (0, plugin_1.getPluginType)(p, platform) === 2 /* PluginType.Incompatible */); const incompatibleCordovaPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 2 /* PluginType.Incompatible */);
(0, plugin_1.printPlugins)(incompatibleCordovaPlugins, platform, 'incompatible'); (0, plugin_1.printPlugins)(incompatibleCordovaPlugins, platform, 'incompatible');
await (0, common_1.checkPlatformVersions)(config, platform); }
async function generateCordovaPackageFiles(cordovaPlugins, config) {
cordovaPlugins.map((plugin) => {
generateCordovaPackageFile(plugin, config);
});
}
async function generateCordovaPackageFile(p, config) {
const iosPlatformVersion = await (0, common_1.getCapacitorPackageVersion)(config, config.ios.name);
const iosVersion = (0, common_2.getMajoriOSVersion)(config);
const headerFiles = (0, plugin_1.getPlatformElement)(p, platform, 'header-file');
let headersText = '';
if (headerFiles.length > 0) {
headersText = `,
publicHeadersPath: "."`;
}
const content = `// swift-tools-version: 5.9
import PackageDescription
let package = Package(
name: "${p.name}",
platforms: [.iOS(.v${iosVersion})],
products: [
.library(
name: "${p.name}",
targets: ["${p.name}"]
)
],
dependencies: [
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "${iosPlatformVersion}")
],
targets: [
.target(
name: "${p.name}",
dependencies: [
.product(name: "Cordova", package: "capacitor-swift-pm")
],
path: "."${headersText}
)
]
)`;
await (0, fs_extra_1.writeFile)((0, path_1.join)(config.ios.cordovaPluginsDirAbs, 'sources', p.name, 'Package.swift'), content);
} }
async function installCocoaPodsPlugins(config, plugins, deployment) { async function installCocoaPodsPlugins(config, plugins, deployment) {
await (0, common_1.runTask)(`Updating iOS native dependencies with ${colors_1.default.input(`${await config.ios.podPath} install`)}`, () => { await (0, common_1.runTask)(`Updating iOS native dependencies with ${colors_1.default.input(`${await config.ios.podPath} install`)}`, () => {
@ -60,31 +105,23 @@ async function updatePodfile(config, plugins, deployment) {
const dependenciesContent = await generatePodFile(config, plugins); const dependenciesContent = await generatePodFile(config, plugins);
const relativeCapacitoriOSPath = await getRelativeCapacitoriOSPath(config); const relativeCapacitoriOSPath = await getRelativeCapacitoriOSPath(config);
const podfilePath = (0, path_1.join)(config.ios.nativeProjectDirAbs, 'Podfile'); const podfilePath = (0, path_1.join)(config.ios.nativeProjectDirAbs, 'Podfile');
let podfileContent = await (0, utils_fs_1.readFile)(podfilePath, { encoding: 'utf-8' }); let podfileContent = await (0, fs_extra_1.readFile)(podfilePath, { encoding: 'utf-8' });
podfileContent = podfileContent.replace(/(def capacitor_pods)[\s\S]+?(\nend)/, `$1${dependenciesContent}$2`); podfileContent = podfileContent.replace(/(def capacitor_pods)[\s\S]+?(\nend)/, `$1${dependenciesContent}$2`);
podfileContent = podfileContent.replace(/(require_relative)[\s\S]+?(@capacitor\/ios\/scripts\/pods_helpers')/, `require_relative '${relativeCapacitoriOSPath}/scripts/pods_helpers'`); podfileContent = podfileContent.replace(/(require_relative)[\s\S]+?(@capacitor\/ios\/scripts\/pods_helpers')/, `require_relative '${relativeCapacitoriOSPath}/scripts/pods_helpers'`);
podfileContent = podfileContent.replace(`def assertDeploymentTarget(installer) await (0, fs_extra_1.writeFile)(podfilePath, podfileContent, { encoding: 'utf-8' });
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
# ensure IPHONEOS_DEPLOYMENT_TARGET is at least 13.0
deployment_target = config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'].to_f
should_upgrade = deployment_target < 13.0 && deployment_target != 0.0
if should_upgrade
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
end
end
end
end`, `require_relative '${relativeCapacitoriOSPath}/scripts/pods_helpers'`);
await (0, utils_fs_1.writeFile)(podfilePath, podfileContent, { encoding: 'utf-8' });
const podPath = await config.ios.podPath; const podPath = await config.ios.podPath;
const useBundler = podPath.startsWith('bundle'); const useBundler = podPath.startsWith('bundle') && (await (0, subprocess_1.isInstalled)('bundle'));
const podCommandExists = await (0, subprocess_1.isInstalled)('pod'); const podCommandExists = await (0, subprocess_1.isInstalled)('pod');
if (useBundler || podCommandExists) { if (useBundler || podCommandExists) {
if (useBundler) { if (useBundler) {
await (0, subprocess_1.runCommand)('bundle', ['exec', 'pod', 'install', ...(deployment ? ['--deployment'] : [])], { cwd: config.ios.nativeProjectDirAbs }); await (0, subprocess_1.runCommand)('bundle', ['exec', 'pod', 'install', ...(deployment ? ['--deployment'] : [])], {
cwd: config.ios.nativeProjectDirAbs,
});
} }
else { else {
await (0, subprocess_1.runCommand)(podPath, ['install', ...(deployment ? ['--deployment'] : [])], { cwd: config.ios.nativeProjectDirAbs }); await (0, subprocess_1.runCommand)(podPath, ['install', ...(deployment ? ['--deployment'] : [])], {
cwd: config.ios.nativeProjectDirAbs,
});
} }
} }
else { else {
@ -106,18 +143,18 @@ async function getRelativeCapacitoriOSPath(config) {
(0, errors_1.fatal)(`Unable to find ${colors_1.default.strong('node_modules/@capacitor/ios')}.\n` + (0, errors_1.fatal)(`Unable to find ${colors_1.default.strong('node_modules/@capacitor/ios')}.\n` +
`Are you sure ${colors_1.default.strong('@capacitor/ios')} is installed?`); `Are you sure ${colors_1.default.strong('@capacitor/ios')} is installed?`);
} }
return (0, fs_1.convertToUnixPath)((0, path_1.relative)(config.ios.nativeProjectDirAbs, await (0, utils_fs_1.realpath)((0, path_1.dirname)(capacitoriOSPath)))); return (0, fs_1.convertToUnixPath)((0, path_1.relative)(config.ios.nativeProjectDirAbs, await (0, fs_extra_1.realpath)((0, path_1.dirname)(capacitoriOSPath))));
} }
async function generatePodFile(config, plugins) { async function generatePodFile(config, plugins) {
const relativeCapacitoriOSPath = await getRelativeCapacitoriOSPath(config); const relativeCapacitoriOSPath = await getRelativeCapacitoriOSPath(config);
const capacitorPlugins = plugins.filter(p => (0, plugin_1.getPluginType)(p, platform) === 0 /* PluginType.Core */); const capacitorPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 0 /* PluginType.Core */);
const pods = await Promise.all(capacitorPlugins.map(async (p) => { const pods = await Promise.all(capacitorPlugins.map(async (p) => {
if (!p.ios) { if (!p.ios) {
return ''; return '';
} }
return ` pod '${p.ios.name}', :path => '${(0, fs_1.convertToUnixPath)((0, path_1.relative)(config.ios.nativeProjectDirAbs, await (0, utils_fs_1.realpath)(p.rootPath)))}'\n`; return ` pod '${p.ios.name}', :path => '${(0, fs_1.convertToUnixPath)((0, path_1.relative)(config.ios.nativeProjectDirAbs, await (0, fs_extra_1.realpath)(p.rootPath)))}'\n`;
})); }));
const cordovaPlugins = plugins.filter(p => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */); const cordovaPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */);
cordovaPlugins.map(async (p) => { cordovaPlugins.map(async (p) => {
const podspecs = (0, plugin_1.getPlatformElement)(p, platform, 'podspec'); const podspecs = (0, plugin_1.getPlatformElement)(p, platform, 'podspec');
podspecs.map((podspec) => { podspecs.map((podspec) => {
@ -140,8 +177,8 @@ async function generatePodFile(config, plugins) {
}); });
}); });
}); });
const staticPlugins = cordovaPlugins.filter(p => (0, cordova_1.needsStaticPod)(p, config)); const staticPlugins = cordovaPlugins.filter((p) => (0, cordova_1.needsStaticPod)(p));
const noStaticPlugins = cordovaPlugins.filter(el => !staticPlugins.includes(el)); const noStaticPlugins = cordovaPlugins.filter((el) => !staticPlugins.includes(el));
if (noStaticPlugins.length > 0) { if (noStaticPlugins.length > 0) {
pods.push(` pod 'CordovaPlugins', :path => '../capacitor-cordova-ios-plugins'\n`); pods.push(` pod 'CordovaPlugins', :path => '../capacitor-cordova-ios-plugins'\n`);
} }
@ -164,16 +201,14 @@ function getFrameworkName(framework) {
} }
return framework.$.src.substr(0, framework.$.src.indexOf('.')); return framework.$.src.substr(0, framework.$.src.indexOf('.'));
} }
return framework.$.src return framework.$.src.substr(0, framework.$.src.indexOf('.')).replace('lib', '');
.substr(0, framework.$.src.indexOf('.'))
.replace('lib', '');
} }
function isFramework(framework) { function isFramework(framework) {
return framework.$.src.split('.').pop().includes('framework'); return framework.$.src.split('.').pop().includes('framework');
} }
async function generateCordovaPodspecs(cordovaPlugins, config) { async function generateCordovaPodspecs(cordovaPlugins, config) {
const staticPlugins = cordovaPlugins.filter(p => (0, cordova_1.needsStaticPod)(p, config)); const staticPlugins = cordovaPlugins.filter((p) => (0, cordova_1.needsStaticPod)(p));
const noStaticPlugins = cordovaPlugins.filter(el => !staticPlugins.includes(el)); const noStaticPlugins = cordovaPlugins.filter((el) => !staticPlugins.includes(el));
generateCordovaPodspec(noStaticPlugins, config, false); generateCordovaPodspec(noStaticPlugins, config, false);
generateCordovaPodspec(staticPlugins, config, true); generateCordovaPodspec(staticPlugins, config, true);
} }
@ -267,7 +302,7 @@ async function generateCordovaPodspec(cordovaPlugins, config, isStatic) {
} }
}); });
}); });
const onlySystemLibraries = systemLibraries.filter(library => removeNoSystem(library, sourceFrameworks)); const onlySystemLibraries = systemLibraries.filter((library) => removeNoSystem(library, sourceFrameworks));
if (weakFrameworks.length > 0) { if (weakFrameworks.length > 0) {
frameworkDeps.push(`s.weak_frameworks = '${weakFrameworks.join(`', '`)}'`); frameworkDeps.push(`s.weak_frameworks = '${weakFrameworks.join(`', '`)}'`);
} }
@ -312,7 +347,7 @@ async function generateCordovaPodspec(cordovaPlugins, config, isStatic) {
s.swift_version = '5.1' s.swift_version = '5.1'
${frameworksString} ${frameworksString}
end`; end`;
await (0, utils_fs_1.writeFile)((0, path_1.join)(config.ios.cordovaPluginsDirAbs, `${name}.podspec`), content); await (0, fs_extra_1.writeFile)((0, path_1.join)(config.ios.cordovaPluginsDirAbs, `${name}.podspec`), content);
} }
function getLinkerFlags(config) { function getLinkerFlags(config) {
var _a; var _a;
@ -328,7 +363,7 @@ async function copyPluginsNativeFiles(config, cordovaPlugins) {
const codeFiles = sourceFiles.concat(headerFiles); const codeFiles = sourceFiles.concat(headerFiles);
const frameworks = (0, plugin_1.getPlatformElement)(p, platform, 'framework'); const frameworks = (0, plugin_1.getPlatformElement)(p, platform, 'framework');
let sourcesFolderName = 'sources'; let sourcesFolderName = 'sources';
if ((0, cordova_1.needsStaticPod)(p, config)) { if ((0, cordova_1.needsStaticPod)(p)) {
sourcesFolderName += 'static'; sourcesFolderName += 'static';
} }
const sourcesFolder = (0, path_1.join)(config.ios.cordovaPluginsDirAbs, sourcesFolderName, p.name); const sourcesFolder = (0, path_1.join)(config.ios.cordovaPluginsDirAbs, sourcesFolderName, p.name);
@ -339,35 +374,33 @@ async function copyPluginsNativeFiles(config, cordovaPlugins) {
fileName = 'lib' + fileName; fileName = 'lib' + fileName;
} }
let destFolder = sourcesFolderName; let destFolder = sourcesFolderName;
if (codeFile.$['compiler-flags'] && if (codeFile.$['compiler-flags'] && codeFile.$['compiler-flags'] === '-fno-objc-arc') {
codeFile.$['compiler-flags'] === '-fno-objc-arc') {
destFolder = 'noarc'; destFolder = 'noarc';
} }
const filePath = (0, plugin_1.getFilePath)(config, p, codeFile.$.src); const filePath = (0, plugin_1.getFilePath)(config, p, codeFile.$.src);
const fileDest = (0, path_1.join)(config.ios.cordovaPluginsDirAbs, destFolder, p.name, fileName); const fileDest = (0, path_1.join)(config.ios.cordovaPluginsDirAbs, destFolder, p.name, fileName);
await (0, utils_fs_1.copy)(filePath, fileDest); await (0, fs_extra_1.copy)(filePath, fileDest);
if (!codeFile.$.framework) { if (!codeFile.$.framework) {
let fileContent = await (0, utils_fs_1.readFile)(fileDest, { encoding: 'utf-8' }); let fileContent = await (0, fs_extra_1.readFile)(fileDest, { encoding: 'utf-8' });
if (fileExt === 'swift') { if (fileExt === 'swift') {
fileContent = 'import Cordova\n' + fileContent; fileContent = 'import Cordova\n' + fileContent;
await (0, utils_fs_1.writeFile)(fileDest, fileContent, { encoding: 'utf-8' }); await (0, fs_extra_1.writeFile)(fileDest, fileContent, { encoding: 'utf-8' });
} }
else { else {
if (fileContent.includes('@import Firebase;')) { if (fileContent.includes('@import Firebase;')) {
fileContent = fileContent.replace('@import Firebase;', '#import <Firebase/Firebase.h>'); fileContent = fileContent.replace('@import Firebase;', '#import <Firebase/Firebase.h>');
await (0, utils_fs_1.writeFile)(fileDest, fileContent, { encoding: 'utf-8' }); await (0, fs_extra_1.writeFile)(fileDest, fileContent, { encoding: 'utf-8' });
} }
if (fileContent.includes('[NSBundle bundleForClass:[self class]]') || if (fileContent.includes('[NSBundle bundleForClass:[self class]]') ||
fileContent.includes('[NSBundle bundleForClass:[CDVCapture class]]')) { fileContent.includes('[NSBundle bundleForClass:[CDVCapture class]]')) {
fileContent = fileContent.replace('[NSBundle bundleForClass:[self class]]', '[NSBundle mainBundle]'); fileContent = fileContent.replace('[NSBundle bundleForClass:[self class]]', '[NSBundle mainBundle]');
fileContent = fileContent.replace('[NSBundle bundleForClass:[CDVCapture class]]', '[NSBundle mainBundle]'); fileContent = fileContent.replace('[NSBundle bundleForClass:[CDVCapture class]]', '[NSBundle mainBundle]');
await (0, utils_fs_1.writeFile)(fileDest, fileContent, { encoding: 'utf-8' }); await (0, fs_extra_1.writeFile)(fileDest, fileContent, { encoding: 'utf-8' });
} }
if (fileContent.includes('[self.webView superview]') || if (fileContent.includes('[self.webView superview]') || fileContent.includes('self.webView.superview')) {
fileContent.includes('self.webView.superview')) {
fileContent = fileContent.replace(/\[self.webView superview\]/g, 'self.viewController.view'); fileContent = fileContent.replace(/\[self.webView superview\]/g, 'self.viewController.view');
fileContent = fileContent.replace(/self.webView.superview/g, 'self.viewController.view'); fileContent = fileContent.replace(/self.webView.superview/g, 'self.viewController.view');
await (0, utils_fs_1.writeFile)(fileDest, fileContent, { encoding: 'utf-8' }); await (0, fs_extra_1.writeFile)(fileDest, fileContent, { encoding: 'utf-8' });
} }
} }
} }
@ -375,17 +408,17 @@ async function copyPluginsNativeFiles(config, cordovaPlugins) {
const resourceFiles = (0, plugin_1.getPlatformElement)(p, platform, 'resource-file'); const resourceFiles = (0, plugin_1.getPlatformElement)(p, platform, 'resource-file');
for (const resourceFile of resourceFiles) { for (const resourceFile of resourceFiles) {
const fileName = resourceFile.$.src.split('/').pop(); const fileName = resourceFile.$.src.split('/').pop();
await (0, utils_fs_1.copy)((0, plugin_1.getFilePath)(config, p, resourceFile.$.src), (0, path_1.join)(config.ios.cordovaPluginsDirAbs, 'resources', fileName)); await (0, fs_extra_1.copy)((0, plugin_1.getFilePath)(config, p, resourceFile.$.src), (0, path_1.join)(config.ios.cordovaPluginsDirAbs, 'resources', fileName));
} }
for (const framework of frameworks) { for (const framework of frameworks) {
if (framework.$.custom && framework.$.custom === 'true') { if (framework.$.custom && framework.$.custom === 'true') {
await (0, utils_fs_1.copy)((0, plugin_1.getFilePath)(config, p, framework.$.src), (0, path_1.join)(sourcesFolder, framework.$.src)); await (0, fs_extra_1.copy)((0, plugin_1.getFilePath)(config, p, framework.$.src), (0, path_1.join)(sourcesFolder, framework.$.src));
} }
} }
} }
} }
async function removePluginsNativeFiles(config) { async function removePluginsNativeFiles(config) {
await (0, utils_fs_1.remove)(config.ios.cordovaPluginsDirAbs); await (0, fs_extra_1.remove)(config.ios.cordovaPluginsDirAbs);
await (0, template_1.extractTemplate)(config.cli.assets.ios.cordovaPluginsTemplateArchiveAbs, config.ios.cordovaPluginsDirAbs); await (0, template_1.extractTemplate)(config.cli.assets.ios.cordovaPluginsTemplateArchiveAbs, config.ios.cordovaPluginsDirAbs);
} }
function filterResources(plugin) { function filterResources(plugin) {
@ -394,12 +427,11 @@ function filterResources(plugin) {
} }
function filterARCFiles(plugin) { function filterARCFiles(plugin) {
const sources = (0, plugin_1.getPlatformElement)(plugin, platform, 'source-file'); const sources = (0, plugin_1.getPlatformElement)(plugin, platform, 'source-file');
const sourcesARC = sources.filter((sourceFile) => sourceFile.$['compiler-flags'] && const sourcesARC = sources.filter((sourceFile) => sourceFile.$['compiler-flags'] && sourceFile.$['compiler-flags'] === '-fno-objc-arc');
sourceFile.$['compiler-flags'] === '-fno-objc-arc');
return sourcesARC.length > 0; return sourcesARC.length > 0;
} }
function removeNoSystem(library, sourceFrameworks) { function removeNoSystem(library, sourceFrameworks) {
const libraries = sourceFrameworks.filter(framework => framework.includes(library)); const libraries = sourceFrameworks.filter((framework) => framework.includes(library));
return libraries.length === 0; return libraries.length === 0;
} }
async function getPluginsTask(config) { async function getPluginsTask(config) {

View file

@ -2,9 +2,9 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.receive = exports.send = void 0; exports.receive = exports.send = void 0;
const tslib_1 = require("tslib"); const tslib_1 = require("tslib");
const utils_fs_1 = require("@ionic/utils-fs");
const utils_subprocess_1 = require("@ionic/utils-subprocess"); const utils_subprocess_1 = require("@ionic/utils-subprocess");
const debug_1 = tslib_1.__importDefault(require("debug")); const debug_1 = tslib_1.__importDefault(require("debug"));
const fs_extra_1 = require("fs-extra");
const https_1 = require("https"); const https_1 = require("https");
const path_1 = require("path"); const path_1 = require("path");
const cli_1 = require("./util/cli"); const cli_1 = require("./util/cli");
@ -14,10 +14,10 @@ const debug = (0, debug_1.default)('capacitor:ipc');
*/ */
async function send(msg) { async function send(msg) {
const dir = cli_1.ENV_PATHS.log; const dir = cli_1.ENV_PATHS.log;
await (0, utils_fs_1.mkdirp)(dir); await (0, fs_extra_1.mkdirp)(dir);
const logPath = (0, path_1.resolve)(dir, 'ipc.log'); const logPath = (0, path_1.resolve)(dir, 'ipc.log');
debug('Sending %O IPC message to forked process (logs: %O)', msg.type, logPath); debug('Sending %O IPC message to forked process (logs: %O)', msg.type, logPath);
const fd = await (0, utils_fs_1.open)(logPath, 'a'); const fd = await (0, fs_extra_1.open)(logPath, 'a');
const p = (0, utils_subprocess_1.fork)(process.argv[1], ['📡'], { stdio: ['ignore', fd, fd, 'ipc'] }); const p = (0, utils_subprocess_1.fork)(process.argv[1], ['📡'], { stdio: ['ignore', fd, fd, 'ipc'] });
p.send(msg); p.send(msg);
p.disconnect(); p.disconnect();
@ -43,10 +43,10 @@ async function receive(msg) {
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
}, response => { }, (response) => {
debug('Sent %O metric to events service (status: %O)', data.name, response.statusCode); debug('Sent %O metric to events service (status: %O)', data.name, response.statusCode);
if (response.statusCode !== 204) { if (response.statusCode !== 204) {
response.on('data', chunk => { response.on('data', (chunk) => {
debug('Bad response from events service. Request body: %O', chunk.toString()); debug('Bad response from events service. Request body: %O', chunk.toString());
}); });
} }

View file

@ -9,9 +9,7 @@ const options = {
colors: colors_1.default, colors: colors_1.default,
stream: process.argv.includes('--json') ? process.stderr : process.stdout, stream: process.argv.includes('--json') ? process.stderr : process.stdout,
}; };
exports.output = (0, term_1.isInteractive)() exports.output = (0, term_1.isInteractive)() ? new cli_framework_output_1.TTYOutputStrategy(options) : new cli_framework_output_1.StreamOutputStrategy(options);
? new cli_framework_output_1.TTYOutputStrategy(options)
: new cli_framework_output_1.StreamOutputStrategy(options);
exports.logger = (0, cli_framework_output_1.createDefaultLogger)({ exports.logger = (0, cli_framework_output_1.createDefaultLogger)({
output: exports.output, output: exports.output,
formatterOptions: { formatterOptions: {

View file

@ -2,7 +2,7 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.getAllElements = exports.getFilePath = exports.getAssets = exports.getJSModules = exports.getPluginType = exports.getPlatformElement = exports.getPluginPlatform = exports.printPlugins = exports.fixName = exports.getDependencies = exports.resolvePlugin = exports.getPlugins = exports.getIncludedPluginPackages = void 0; exports.getAllElements = exports.getFilePath = exports.getAssets = exports.getJSModules = exports.getPluginType = exports.getPlatformElement = exports.getPluginPlatform = exports.printPlugins = exports.fixName = exports.getDependencies = exports.resolvePlugin = exports.getPlugins = exports.getIncludedPluginPackages = void 0;
const tslib_1 = require("tslib"); const tslib_1 = require("tslib");
const utils_fs_1 = require("@ionic/utils-fs"); const fs_extra_1 = require("fs-extra");
const path_1 = require("path"); const path_1 = require("path");
const colors_1 = tslib_1.__importDefault(require("./colors")); const colors_1 = tslib_1.__importDefault(require("./colors"));
const errors_1 = require("./errors"); const errors_1 = require("./errors");
@ -31,11 +31,10 @@ async function resolvePlugin(config, name) {
try { try {
const packagePath = (0, node_1.resolveNode)(config.app.rootDir, name, 'package.json'); const packagePath = (0, node_1.resolveNode)(config.app.rootDir, name, 'package.json');
if (!packagePath) { if (!packagePath) {
(0, errors_1.fatal)(`Unable to find ${colors_1.default.strong(`node_modules/${name}`)}.\n` + (0, errors_1.fatal)(`Unable to find ${colors_1.default.strong(`node_modules/${name}`)}.\n` + `Are you sure ${colors_1.default.strong(name)} is installed?`);
`Are you sure ${colors_1.default.strong(name)} is installed?`);
} }
const rootPath = (0, path_1.dirname)(packagePath); const rootPath = (0, path_1.dirname)(packagePath);
const meta = await (0, utils_fs_1.readJSON)(packagePath); const meta = await (0, fs_extra_1.readJSON)(packagePath);
if (!meta) { if (!meta) {
return null; return null;
} }
@ -79,7 +78,7 @@ function fixName(name) {
.replace(/\//g, '_') .replace(/\//g, '_')
.replace(/-/g, '_') .replace(/-/g, '_')
.replace(/@/g, '') .replace(/@/g, '')
.replace(/_\w/g, m => m[1].toUpperCase()); .replace(/_\w/g, (m) => m[1].toUpperCase());
return name.charAt(0).toUpperCase() + name.slice(1); return name.charAt(0).toUpperCase() + name.slice(1);
} }
exports.fixName = fixName; exports.fixName = fixName;
@ -100,7 +99,7 @@ function printPlugins(plugins, platform, type = 'capacitor') {
msg = `Found ${plugins.length} Capacitor plugin${plural} for ${colors_1.default.strong(platform)}:\n`; msg = `Found ${plugins.length} Capacitor plugin${plural} for ${colors_1.default.strong(platform)}:\n`;
break; break;
} }
msg += plugins.map(p => `${p.id}${colors_1.default.weak(`@${p.version}`)}`).join('\n'); msg += plugins.map((p) => `${p.id}${colors_1.default.weak(`@${p.version}`)}`).join('\n');
log_1.logger.info(msg); log_1.logger.info(msg);
} }
exports.printPlugins = printPlugins; exports.printPlugins = printPlugins;
@ -155,10 +154,7 @@ function getFilePath(config, plugin, path) {
if (path.startsWith('node_modules')) { if (path.startsWith('node_modules')) {
let pathSegments = path.split('/').slice(1); let pathSegments = path.split('/').slice(1);
if (pathSegments[0].startsWith('@')) { if (pathSegments[0].startsWith('@')) {
pathSegments = [ pathSegments = [pathSegments[0] + '/' + pathSegments[1], ...pathSegments.slice(2)];
pathSegments[0] + '/' + pathSegments[1],
...pathSegments.slice(2),
];
} }
const filePath = (0, node_1.resolveNode)(config.app.rootDir, ...pathSegments); const filePath = (0, node_1.resolveNode)(config.app.rootDir, ...pathSegments);
if (!filePath) { if (!filePath) {

View file

@ -2,8 +2,8 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.writeConfig = exports.readConfig = void 0; exports.writeConfig = exports.readConfig = void 0;
const tslib_1 = require("tslib"); const tslib_1 = require("tslib");
const utils_fs_1 = require("@ionic/utils-fs");
const debug_1 = tslib_1.__importDefault(require("debug")); const debug_1 = tslib_1.__importDefault(require("debug"));
const fs_extra_1 = require("fs-extra");
const path_1 = require("path"); const path_1 = require("path");
const cli_1 = require("./util/cli"); const cli_1 = require("./util/cli");
const uuid_1 = require("./util/uuid"); const uuid_1 = require("./util/uuid");
@ -13,7 +13,7 @@ const SYSCONFIG_PATH = (0, path_1.resolve)(cli_1.ENV_PATHS.config, SYSCONFIG_FIL
async function readConfig() { async function readConfig() {
debug('Reading from %O', SYSCONFIG_PATH); debug('Reading from %O', SYSCONFIG_PATH);
try { try {
return await (0, utils_fs_1.readJSON)(SYSCONFIG_PATH); return await (0, fs_extra_1.readJSON)(SYSCONFIG_PATH);
} }
catch (e) { catch (e) {
if (e.code !== 'ENOENT') { if (e.code !== 'ENOENT') {
@ -29,7 +29,7 @@ async function readConfig() {
exports.readConfig = readConfig; exports.readConfig = readConfig;
async function writeConfig(sysconfig) { async function writeConfig(sysconfig) {
debug('Writing to %O', SYSCONFIG_PATH); debug('Writing to %O', SYSCONFIG_PATH);
await (0, utils_fs_1.mkdirp)((0, path_1.dirname)(SYSCONFIG_PATH)); await (0, fs_extra_1.mkdirp)((0, path_1.dirname)(SYSCONFIG_PATH));
await (0, utils_fs_1.writeJSON)(SYSCONFIG_PATH, sysconfig, { spaces: '\t' }); await (0, fs_extra_1.writeJSON)(SYSCONFIG_PATH, sysconfig, { spaces: '\t' });
} }
exports.writeConfig = writeConfig; exports.writeConfig = writeConfig;

View file

@ -2,8 +2,8 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.addCommand = void 0; exports.addCommand = void 0;
const tslib_1 = require("tslib"); const tslib_1 = require("tslib");
const utils_fs_1 = require("@ionic/utils-fs");
const utils_terminal_1 = require("@ionic/utils-terminal"); const utils_terminal_1 = require("@ionic/utils-terminal");
const fs_extra_1 = require("fs-extra");
const add_1 = require("../android/add"); const add_1 = require("../android/add");
const common_1 = require("../android/common"); const common_1 = require("../android/common");
const colors_1 = tslib_1.__importDefault(require("../colors")); const colors_1 = tslib_1.__importDefault(require("../colors"));
@ -47,14 +47,10 @@ async function addCommand(config, selectedPlatformName) {
`${colors_1.default.strong('WARNING')}: Your native project will be completely removed.`); `${colors_1.default.strong('WARNING')}: Your native project will be completely removed.`);
} }
try { try {
await (0, common_2.check)([ await (0, common_2.check)([() => (0, common_2.checkPackage)(), () => (0, common_2.checkAppConfig)(config), ...addChecks(config, platformName)]);
() => (0, common_2.checkPackage)(),
() => (0, common_2.checkAppConfig)(config),
...addChecks(config, platformName),
]);
await doAdd(config, platformName); await doAdd(config, platformName);
await editPlatforms(config, platformName); await editPlatforms(config, platformName);
if (await (0, utils_fs_1.pathExists)(config.app.webDirAbs)) { if (await (0, fs_extra_1.pathExists)(config.app.webDirAbs)) {
await (0, sync_1.sync)(config, platformName, false, false); await (0, sync_1.sync)(config, platformName, false, false);
if (platformName === config.android.name) { if (platformName === config.android.name) {
await (0, common_2.runTask)('Syncing Gradle', async () => { await (0, common_2.runTask)('Syncing Gradle', async () => {
@ -82,10 +78,7 @@ function printNextSteps(platformName) {
} }
function addChecks(config, platformName) { function addChecks(config, platformName) {
if (platformName === config.ios.name) { if (platformName === config.ios.name) {
return [ return [() => (0, common_3.checkIOSPackage)(config), () => (0, common_3.checkBundler)(config) || (0, common_3.checkCocoaPods)(config)];
() => (0, common_3.checkIOSPackage)(config),
() => (0, common_3.checkBundler)(config) || (0, common_3.checkCocoaPods)(config),
];
} }
else if (platformName === config.android.name) { else if (platformName === config.android.name) {
return [() => (0, common_1.checkAndroidPackage)(config)]; return [() => (0, common_1.checkAndroidPackage)(config)];

View file

@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.build = exports.buildCommand = void 0; exports.build = exports.buildCommand = void 0;
const build_1 = require("../android/build"); const build_1 = require("../android/build");
const common_1 = require("../common"); const common_1 = require("../common");
const definitions_1 = require("../definitions");
const errors_1 = require("../errors"); const errors_1 = require("../errors");
const build_2 = require("../ios/build"); const build_2 = require("../ios/build");
async function buildCommand(config, selectedPlatformName, buildOptions) { async function buildCommand(config, selectedPlatformName, buildOptions) {
@ -21,15 +22,15 @@ async function buildCommand(config, selectedPlatformName, buildOptions) {
keystorepath: buildOptions.keystorepath || config.android.buildOptions.keystorePath, keystorepath: buildOptions.keystorepath || config.android.buildOptions.keystorePath,
keystorepass: buildOptions.keystorepass || config.android.buildOptions.keystorePassword, keystorepass: buildOptions.keystorepass || config.android.buildOptions.keystorePassword,
keystorealias: buildOptions.keystorealias || config.android.buildOptions.keystoreAlias, keystorealias: buildOptions.keystorealias || config.android.buildOptions.keystoreAlias,
keystorealiaspass: buildOptions.keystorealiaspass || keystorealiaspass: buildOptions.keystorealiaspass || config.android.buildOptions.keystoreAliasPassword,
config.android.buildOptions.keystoreAliasPassword, androidreleasetype: buildOptions.androidreleasetype || config.android.buildOptions.releaseType || 'AAB',
androidreleasetype: buildOptions.androidreleasetype || signingtype: buildOptions.signingtype || config.android.buildOptions.signingType || 'jarsigner',
config.android.buildOptions.releaseType ||
'AAB',
signingtype: buildOptions.signingtype ||
config.android.buildOptions.signingType ||
'jarsigner',
configuration: buildOptions.configuration || 'Release', configuration: buildOptions.configuration || 'Release',
xcodeTeamId: buildOptions.xcodeTeamId || config.ios.buildOptions.teamId,
xcodeExportMethod: buildOptions.xcodeExportMethod || config.ios.buildOptions.exportMethod || definitions_1.XcodeExportMethod.AppStoreConnect,
xcodeSigningType: buildOptions.xcodeSigningType || config.ios.buildOptions.xcodeSigningStyle || 'automatic',
xcodeSigningCertificate: buildOptions.xcodeSigningCertificate || config.ios.buildOptions.signingCertificate,
xcodeProvisioningProfile: buildOptions.xcodeProvisioningProfile || config.ios.buildOptions.provisioningProfile,
}; };
try { try {
await build(config, platformName, buildCommandOptions); await build(config, platformName, buildCommandOptions);
@ -58,5 +59,5 @@ async function build(config, platformName, buildOptions) {
} }
exports.build = build; exports.build = build;
function createBuildablePlatformFilter(config) { function createBuildablePlatformFilter(config) {
return platform => platform === config.ios.name || platform === config.android.name; return (platform) => platform === config.ios.name || platform === config.android.name;
} }

View file

@ -15,10 +15,7 @@ async function configCommand(config, json) {
} }
exports.configCommand = configCommand; exports.configCommand = configCommand;
async function deepAwait(obj) { async function deepAwait(obj) {
if (obj && if (obj && !Array.isArray(obj) && typeof obj === 'object' && obj.constructor === Object) {
!Array.isArray(obj) &&
typeof obj === 'object' &&
obj.constructor === Object) {
const o = {}; const o = {};
for (const [k, v] of Object.entries(obj)) { for (const [k, v] of Object.entries(obj)) {
o[k] = await deepAwait(v); o[k] = await deepAwait(v);

View file

@ -2,7 +2,7 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.copy = exports.copyCommand = void 0; exports.copy = exports.copyCommand = void 0;
const tslib_1 = require("tslib"); const tslib_1 = require("tslib");
const utils_fs_1 = require("@ionic/utils-fs"); const fs_extra_1 = require("fs-extra");
const path_1 = require("path"); const path_1 = require("path");
const colors_1 = tslib_1.__importDefault(require("../colors")); const colors_1 = tslib_1.__importDefault(require("../colors"));
const common_1 = require("../common"); const common_1 = require("../common");
@ -13,7 +13,6 @@ const log_1 = require("../log");
const plugin_1 = require("../plugin"); const plugin_1 = require("../plugin");
const iosplugin_1 = require("../util/iosplugin"); const iosplugin_1 = require("../util/iosplugin");
const promise_1 = require("../util/promise"); const promise_1 = require("../util/promise");
const copy_1 = require("../web/copy");
const sourcemaps_1 = require("./sourcemaps"); const sourcemaps_1 = require("./sourcemaps");
async function copyCommand(config, selectedPlatformName, inline = false) { async function copyCommand(config, selectedPlatformName, inline = false) {
var _a; var _a;
@ -29,7 +28,7 @@ async function copyCommand(config, selectedPlatformName, inline = false) {
else { else {
const platforms = await (0, common_1.selectPlatforms)(config, selectedPlatformName); const platforms = await (0, common_1.selectPlatforms)(config, selectedPlatformName);
try { try {
await (0, promise_1.allSerial)(platforms.map(platformName => () => copy(config, platformName, inline))); await (0, promise_1.allSerial)(platforms.map((platformName) => () => copy(config, platformName, inline)));
} }
catch (e) { catch (e) {
if ((0, errors_1.isFatal)(e)) { if ((0, errors_1.isFatal)(e)) {
@ -50,17 +49,15 @@ async function copy(config, platformName, inline = false) {
await (0, common_1.runHooks)(config, platformName, config.app.rootDir, 'capacitor:copy:before'); await (0, common_1.runHooks)(config, platformName, config.app.rootDir, 'capacitor:copy:before');
const allPlugins = await (0, plugin_1.getPlugins)(config, platformName); const allPlugins = await (0, plugin_1.getPlugins)(config, platformName);
let usesFederatedCapacitor = false; let usesFederatedCapacitor = false;
if (allPlugins.filter(plugin => plugin.id === '@ionic-enterprise/federated-capacitor').length > 0) { if (allPlugins.filter((plugin) => plugin.id === '@ionic-enterprise/federated-capacitor').length > 0) {
usesFederatedCapacitor = true; usesFederatedCapacitor = true;
} }
let usesLiveUpdates = false; let usesLiveUpdates = false;
if (allPlugins.filter(plugin => plugin.id === '@capacitor/live-updates') if (allPlugins.filter((plugin) => plugin.id === '@capacitor/live-updates').length > 0) {
.length > 0) {
usesLiveUpdates = true; usesLiveUpdates = true;
} }
let usesSSLPinning = false; let usesSSLPinning = false;
if (allPlugins.filter(plugin => plugin.id === '@ionic-enterprise/ssl-pinning') if (allPlugins.filter((plugin) => plugin.id === '@ionic-enterprise/ssl-pinning').length > 0) {
.length > 0) {
usesSSLPinning = true; usesSSLPinning = true;
} }
if (platformName === config.ios.name) { if (platformName === config.ios.name) {
@ -110,9 +107,6 @@ async function copy(config, platformName, inline = false) {
if (usesFederatedCapacitor) { if (usesFederatedCapacitor) {
log_1.logger.info('FederatedCapacitor Plugin installed, skipping web bundling...'); log_1.logger.info('FederatedCapacitor Plugin installed, skipping web bundling...');
} }
else {
await (0, copy_1.copyWeb)(config);
}
} }
else { else {
throw `Platform ${platformName} is not valid.`; throw `Platform ${platformName} is not valid.`;
@ -129,9 +123,10 @@ async function copyCapacitorConfig(config, nativeAbsDir) {
const nativeConfigFile = 'capacitor.config.json'; const nativeConfigFile = 'capacitor.config.json';
const nativeConfigFilePath = (0, path_1.join)(nativeAbsDir, nativeConfigFile); const nativeConfigFilePath = (0, path_1.join)(nativeAbsDir, nativeConfigFile);
await (0, common_1.runTask)(`Creating ${colors_1.default.strong(nativeConfigFile)} in ${nativeRelDir}`, async () => { await (0, common_1.runTask)(`Creating ${colors_1.default.strong(nativeConfigFile)} in ${nativeRelDir}`, async () => {
var _a; var _a, _b;
(_a = config.app.extConfig.android) === null || _a === void 0 ? true : delete _a.buildOptions; (_a = config.app.extConfig.android) === null || _a === void 0 ? true : delete _a.buildOptions;
await (0, utils_fs_1.writeJSON)(nativeConfigFilePath, config.app.extConfig, { (_b = config.app.extConfig.ios) === null || _b === void 0 ? true : delete _b.buildOptions;
await (0, fs_extra_1.writeJSON)(nativeConfigFilePath, config.app.extConfig, {
spaces: '\t', spaces: '\t',
}); });
}); });
@ -140,14 +135,14 @@ async function copyWebDir(config, nativeAbsDir, webAbsDir) {
var _a; var _a;
const webRelDir = (0, path_1.basename)(webAbsDir); const webRelDir = (0, path_1.basename)(webAbsDir);
const nativeRelDir = (0, path_1.relative)(config.app.rootDir, nativeAbsDir); const nativeRelDir = (0, path_1.relative)(config.app.rootDir, nativeAbsDir);
if (((_a = config.app.extConfig.server) === null || _a === void 0 ? void 0 : _a.url) && !(await (0, utils_fs_1.pathExists)(webAbsDir))) { if (((_a = config.app.extConfig.server) === null || _a === void 0 ? void 0 : _a.url) && !(await (0, fs_extra_1.pathExists)(webAbsDir))) {
log_1.logger.warn(`Cannot copy web assets from ${colors_1.default.strong(webRelDir)} to ${nativeRelDir}\n` + log_1.logger.warn(`Cannot copy web assets from ${colors_1.default.strong(webRelDir)} to ${nativeRelDir}\n` +
`Web asset directory specified by ${colors_1.default.input('webDir')} does not exist. This is not an error because ${colors_1.default.input('server.url')} is set in config.`); `Web asset directory specified by ${colors_1.default.input('webDir')} does not exist. This is not an error because ${colors_1.default.input('server.url')} is set in config.`);
return; return;
} }
await (0, common_1.runTask)(`Copying web assets from ${colors_1.default.strong(webRelDir)} to ${nativeRelDir}`, async () => { await (0, common_1.runTask)(`Copying web assets from ${colors_1.default.strong(webRelDir)} to ${nativeRelDir}`, async () => {
await (0, utils_fs_1.remove)(nativeAbsDir); await (0, fs_extra_1.remove)(nativeAbsDir);
return (0, utils_fs_1.copy)(webAbsDir, nativeAbsDir); return (0, fs_extra_1.copy)(webAbsDir, nativeAbsDir);
}); });
} }
async function copyFederatedWebDirs(config, nativeAbsDir) { async function copyFederatedWebDirs(config, nativeAbsDir) {
@ -165,7 +160,7 @@ async function copyFederatedWebDirs(config, nativeAbsDir) {
throw `FederatedCapacitor plugin is present but there is a problem with the apps defined in the config.`; throw `FederatedCapacitor plugin is present but there is a problem with the apps defined in the config.`;
} }
const copyApps = () => { const copyApps = () => {
return federatedConfig.apps.map(app => { return federatedConfig.apps.map((app) => {
const appDir = (0, path_1.resolve)(config.app.rootDir, app.webDir); const appDir = (0, path_1.resolve)(config.app.rootDir, app.webDir);
return copyWebDir(config, (0, path_1.resolve)(nativeAbsDir, app.name), appDir); return copyWebDir(config, (0, path_1.resolve)(nativeAbsDir, app.name), appDir);
}); });
@ -177,27 +172,26 @@ async function copyFederatedWebDirs(config, nativeAbsDir) {
} }
} }
function isFederatedApp(config) { function isFederatedApp(config) {
return (config.webDir !== undefined && return config.webDir !== undefined && config.name !== undefined;
config.name !== undefined);
} }
async function copySecureLiveUpdatesKey(secureLiveUpdatesKeyFile, rootDir, nativeAbsDir) { async function copySecureLiveUpdatesKey(secureLiveUpdatesKeyFile, rootDir, nativeAbsDir) {
const keyAbsFromPath = (0, path_1.join)(rootDir, secureLiveUpdatesKeyFile); const keyAbsFromPath = (0, path_1.join)(rootDir, secureLiveUpdatesKeyFile);
const keyAbsToPath = (0, path_1.join)(nativeAbsDir, (0, path_1.basename)(keyAbsFromPath)); const keyAbsToPath = (0, path_1.join)(nativeAbsDir, (0, path_1.basename)(keyAbsFromPath));
const keyRelToDir = (0, path_1.relative)(rootDir, nativeAbsDir); const keyRelToDir = (0, path_1.relative)(rootDir, nativeAbsDir);
if (!(await (0, utils_fs_1.pathExists)(keyAbsFromPath))) { if (!(await (0, fs_extra_1.pathExists)(keyAbsFromPath))) {
log_1.logger.warn(`Cannot copy Secure Live Updates signature file from ${colors_1.default.strong(keyAbsFromPath)} to ${keyRelToDir}\n` + log_1.logger.warn(`Cannot copy Secure Live Updates signature file from ${colors_1.default.strong(keyAbsFromPath)} to ${keyRelToDir}\n` +
`Signature file does not exist at specified key path.`); `Signature file does not exist at specified key path.`);
return; return;
} }
await (0, common_1.runTask)(`Copying Secure Live Updates key from ${colors_1.default.strong(secureLiveUpdatesKeyFile)} to ${keyRelToDir}`, async () => { await (0, common_1.runTask)(`Copying Secure Live Updates key from ${colors_1.default.strong(secureLiveUpdatesKeyFile)} to ${keyRelToDir}`, async () => {
return (0, utils_fs_1.copy)(keyAbsFromPath, keyAbsToPath); return (0, fs_extra_1.copy)(keyAbsFromPath, keyAbsToPath);
}); });
} }
async function copySSLCert(sslCertPaths, rootDir, targetDir) { async function copySSLCert(sslCertPaths, rootDir, targetDir) {
const validCertPaths = []; const validCertPaths = [];
for (const sslCertPath of sslCertPaths) { for (const sslCertPath of sslCertPaths) {
const certAbsFromPath = (0, path_1.join)(rootDir, sslCertPath); const certAbsFromPath = (0, path_1.join)(rootDir, sslCertPath);
if (!(await (0, utils_fs_1.pathExists)(certAbsFromPath))) { if (!(await (0, fs_extra_1.pathExists)(certAbsFromPath))) {
log_1.logger.warn(`Cannot copy SSL Certificate file from ${colors_1.default.strong(certAbsFromPath)}\n` + log_1.logger.warn(`Cannot copy SSL Certificate file from ${colors_1.default.strong(certAbsFromPath)}\n` +
`SSL Certificate does not exist at specified path.`); `SSL Certificate does not exist at specified path.`);
return; return;
@ -209,7 +203,7 @@ async function copySSLCert(sslCertPaths, rootDir, targetDir) {
await (0, common_1.runTask)(`Copying SSL Certificates from to ${certsDirRelToDir}`, async () => { await (0, common_1.runTask)(`Copying SSL Certificates from to ${certsDirRelToDir}`, async () => {
const promises = []; const promises = [];
for (const certPath of validCertPaths) { for (const certPath of validCertPaths) {
promises.push((0, utils_fs_1.copy)(certPath, (0, path_1.join)(certsDirAbsToPath, (0, path_1.basename)(certPath)))); promises.push((0, fs_extra_1.copy)(certPath, (0, path_1.join)(certsDirAbsToPath, (0, path_1.basename)(certPath))));
} }
return Promise.all(promises); return Promise.all(promises);
}); });

View file

@ -5,7 +5,6 @@ const tslib_1 = require("tslib");
const colors_1 = tslib_1.__importDefault(require("../colors")); const colors_1 = tslib_1.__importDefault(require("../colors"));
const errors_1 = require("../errors"); const errors_1 = require("../errors");
async function createCommand() { async function createCommand() {
(0, errors_1.fatal)(`The create command has been removed.\n` + (0, errors_1.fatal)(`The create command has been removed.\n` + `Use ${colors_1.default.input('npm init @capacitor/app')}`);
`Use ${colors_1.default.input('npm init @capacitor/app')}`);
} }
exports.createCommand = createCommand; exports.createCommand = createCommand;

View file

@ -2,7 +2,7 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.doctor = exports.doctorCore = exports.doctorCommand = void 0; exports.doctor = exports.doctorCore = exports.doctorCommand = void 0;
const tslib_1 = require("tslib"); const tslib_1 = require("tslib");
const utils_fs_1 = require("@ionic/utils-fs"); const fs_extra_1 = require("fs-extra");
const doctor_1 = require("../android/doctor"); const doctor_1 = require("../android/doctor");
const colors_1 = tslib_1.__importDefault(require("../colors")); const colors_1 = tslib_1.__importDefault(require("../colors"));
const common_1 = require("../common"); const common_1 = require("../common");
@ -15,7 +15,7 @@ async function doctorCommand(config, selectedPlatformName) {
log_1.output.write(`${(0, emoji_1.emoji)('💊', '')} ${colors_1.default.strong('Capacitor Doctor')} ${(0, emoji_1.emoji)('💊', '')} \n\n`); log_1.output.write(`${(0, emoji_1.emoji)('💊', '')} ${colors_1.default.strong('Capacitor Doctor')} ${(0, emoji_1.emoji)('💊', '')} \n\n`);
await doctorCore(config); await doctorCore(config);
const platforms = await (0, common_1.selectPlatforms)(config, selectedPlatformName); const platforms = await (0, common_1.selectPlatforms)(config, selectedPlatformName);
await Promise.all(platforms.map(platformName => { await Promise.all(platforms.map((platformName) => {
return doctor(config, platformName); return doctor(config, platformName);
})); }));
} }
@ -38,12 +38,7 @@ async function doctorCore(config) {
} }
exports.doctorCore = doctorCore; exports.doctorCore = doctorCore;
async function printInstalledPackages(config) { async function printInstalledPackages(config) {
const packageNames = [ const packageNames = ['@capacitor/cli', '@capacitor/core', '@capacitor/android', '@capacitor/ios'];
'@capacitor/cli',
'@capacitor/core',
'@capacitor/android',
'@capacitor/ios',
];
await Promise.all(packageNames.map(async (packageName) => { await Promise.all(packageNames.map(async (packageName) => {
const packagePath = (0, node_1.resolveNode)(config.app.rootDir, packageName, 'package.json'); const packagePath = (0, node_1.resolveNode)(config.app.rootDir, packageName, 'package.json');
await printPackageVersion(packageName, packagePath); await printPackageVersion(packageName, packagePath);
@ -52,7 +47,7 @@ async function printInstalledPackages(config) {
async function printPackageVersion(packageName, packagePath) { async function printPackageVersion(packageName, packagePath) {
let version; let version;
if (packagePath) { if (packagePath) {
version = (await (0, utils_fs_1.readJSON)(packagePath)).version; version = (await (0, fs_extra_1.readJSON)(packagePath)).version;
} }
log_1.output.write(` ${packageName}: ${colors_1.default.weak(version || 'not installed')}\n`); log_1.output.write(` ${packageName}: ${colors_1.default.weak(version || 'not installed')}\n`);
} }

View file

@ -14,7 +14,7 @@ const log_1 = require("../log");
const sysconfig_1 = require("../sysconfig"); const sysconfig_1 = require("../sysconfig");
const node_1 = require("../util/node"); const node_1 = require("../util/node");
const term_1 = require("../util/term"); const term_1 = require("../util/term");
async function initCommand(config, name, id, webDirFromCLI) { async function initCommand(config, name, id, webDirFromCLI, skipAppIDValidation) {
var _a, _b; var _a, _b;
try { try {
if (!(0, term_1.checkInteractive)(name, id)) { if (!(0, term_1.checkInteractive)(name, id)) {
@ -30,11 +30,13 @@ async function initCommand(config, name, id, webDirFromCLI) {
const appId = await getAppId(config, id); const appId = await getAppId(config, id);
const webDir = (0, term_1.isInteractive)() const webDir = (0, term_1.isInteractive)()
? await getWebDir(config, webDirFromCLI) ? await getWebDir(config, webDirFromCLI)
: (_a = webDirFromCLI !== null && webDirFromCLI !== void 0 ? webDirFromCLI : config.app.extConfig.webDir) !== null && _a !== void 0 ? _a : 'www'; : ((_a = webDirFromCLI !== null && webDirFromCLI !== void 0 ? webDirFromCLI : config.app.extConfig.webDir) !== null && _a !== void 0 ? _a : 'www');
await (0, common_1.check)([ if (skipAppIDValidation === true) {
() => (0, common_1.checkAppName)(config, appName), await (0, common_1.check)([() => (0, common_1.checkAppName)(config, appName)]);
() => (0, common_1.checkAppId)(config, appId), }
]); else {
await (0, common_1.check)([() => (0, common_1.checkAppName)(config, appName), () => (0, common_1.checkAppId)(config, appId)]);
}
const cordova = await (0, cordova_1.getCordovaPreferences)(config); const cordova = await (0, cordova_1.getCordovaPreferences)(config);
await runMergeConfig(config, { await runMergeConfig(config, {
appId, appId,
@ -45,8 +47,7 @@ async function initCommand(config, name, id, webDirFromCLI) {
} }
catch (e) { catch (e) {
if (!(0, errors_1.isFatal)(e)) { if (!(0, errors_1.isFatal)(e)) {
log_1.output.write('Usage: npx cap init appName appId\n' + log_1.output.write('Usage: npx cap init appName appId\n' + 'Example: npx cap init "My App" "com.example.myapp"\n\n');
'Example: npx cap init "My App" "com.example.myapp"\n\n');
(0, errors_1.fatal)((_b = e.stack) !== null && _b !== void 0 ? _b : e); (0, errors_1.fatal)((_b = e.stack) !== null && _b !== void 0 ? _b : e);
} }
throw e; throw e;
@ -61,9 +62,7 @@ async function getName(config, name) {
type: 'text', type: 'text',
name: 'name', name: 'name',
message: `Name`, message: `Name`,
initial: config.app.appName initial: config.app.appName ? config.app.appName : ((_a = config.app.package.name) !== null && _a !== void 0 ? _a : 'App'),
? config.app.appName
: (_a = config.app.package.name) !== null && _a !== void 0 ? _a : 'App',
}); });
return answers.name; return answers.name;
} }

View file

@ -14,7 +14,7 @@ async function listCommand(config, selectedPlatformName) {
var _a; var _a;
const platforms = await (0, common_2.selectPlatforms)(config, selectedPlatformName); const platforms = await (0, common_2.selectPlatforms)(config, selectedPlatformName);
try { try {
await (0, promise_1.allSerial)(platforms.map(platformName => () => list(config, platformName))); await (0, promise_1.allSerial)(platforms.map((platformName) => () => list(config, platformName)));
} }
catch (e) { catch (e) {
if ((0, errors_1.isFatal)(e)) { if ((0, errors_1.isFatal)(e)) {
@ -40,11 +40,11 @@ async function list(config, platform) {
else { else {
throw `Platform ${colors_1.default.input(platform)} is not valid.`; throw `Platform ${colors_1.default.input(platform)} is not valid.`;
} }
const capacitorPlugins = plugins.filter(p => (0, plugin_1.getPluginType)(p, platform) === 0 /* PluginType.Core */); const capacitorPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 0 /* PluginType.Core */);
(0, plugin_1.printPlugins)(capacitorPlugins, platform); (0, plugin_1.printPlugins)(capacitorPlugins, platform);
const cordovaPlugins = plugins.filter(p => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */); const cordovaPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 1 /* PluginType.Cordova */);
(0, plugin_1.printPlugins)(cordovaPlugins, platform, 'cordova'); (0, plugin_1.printPlugins)(cordovaPlugins, platform, 'cordova');
const incompatibleCordovaPlugins = plugins.filter(p => (0, plugin_1.getPluginType)(p, platform) === 2 /* PluginType.Incompatible */); const incompatibleCordovaPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, platform) === 2 /* PluginType.Incompatible */);
(0, plugin_1.printPlugins)(incompatibleCordovaPlugins, platform, 'incompatible'); (0, plugin_1.printPlugins)(incompatibleCordovaPlugins, platform, 'incompatible');
} }
exports.list = list; exports.list = list;

View file

@ -0,0 +1,19 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.migrateToSPM = void 0;
const errors_1 = require("../errors");
const log_1 = require("../log");
const spm_1 = require("../util/spm");
const update_1 = require("./update");
async function migrateToSPM(config) {
if ((await (0, spm_1.checkPackageManager)(config)) == 'SPM') {
(0, errors_1.fatal)('Capacitor project is already using SPM, exiting.');
}
await (0, spm_1.extractSPMPackageDirectory)(config);
await (0, spm_1.runCocoapodsDeintegrate)(config);
await (0, spm_1.removeCocoapodsFiles)(config);
await (0, spm_1.addInfoPlistDebugIfNeeded)(config);
await (0, update_1.update)(config, 'ios', true);
log_1.logger.info('To complete migration follow the manual steps at https://capacitorjs.com/docs/ios/spm#using-our-migration-tool');
}
exports.migrateToSPM = migrateToSPM;

View file

@ -2,28 +2,25 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.patchOldCapacitorPlugins = exports.migrateCommand = void 0; exports.patchOldCapacitorPlugins = exports.migrateCommand = void 0;
const tslib_1 = require("tslib"); const tslib_1 = require("tslib");
const utils_fs_1 = require("@ionic/utils-fs"); const fs_extra_1 = require("fs-extra");
const path_1 = require("path"); const path_1 = require("path");
const rimraf_1 = tslib_1.__importDefault(require("rimraf")); const rimraf_1 = require("rimraf");
const semver_1 = require("semver"); const semver_1 = require("semver");
const common_1 = require("../android/common"); const common_1 = require("../android/common");
const colors_1 = tslib_1.__importDefault(require("../colors")); const colors_1 = tslib_1.__importDefault(require("../colors"));
const common_2 = require("../common"); const common_2 = require("../common");
const errors_1 = require("../errors"); const errors_1 = require("../errors");
const common_3 = require("../ios/common");
const log_1 = require("../log"); const log_1 = require("../log");
const plugin_1 = require("../plugin"); const plugin_1 = require("../plugin");
const fs_1 = require("../util/fs"); const fs_1 = require("../util/fs");
const node_1 = require("../util/node"); const node_1 = require("../util/node");
const spm_1 = require("../util/spm");
const subprocess_1 = require("../util/subprocess"); const subprocess_1 = require("../util/subprocess");
const template_1 = require("../util/template"); const template_1 = require("../util/template");
// eslint-disable-next-line prefer-const // eslint-disable-next-line prefer-const
let allDependencies = {}; let allDependencies = {};
const libs = [ const libs = ['@capacitor/core', '@capacitor/cli', '@capacitor/ios', '@capacitor/android'];
'@capacitor/core',
'@capacitor/cli',
'@capacitor/ios',
'@capacitor/android',
];
const plugins = [ const plugins = [
'@capacitor/action-sheet', '@capacitor/action-sheet',
'@capacitor/app', '@capacitor/app',
@ -50,21 +47,22 @@ const plugins = [
'@capacitor/text-zoom', '@capacitor/text-zoom',
'@capacitor/toast', '@capacitor/toast',
]; ];
const coreVersion = '^6.0.0'; const coreVersion = '^7.0.0';
const pluginVersion = '^6.0.0'; const pluginVersion = '^7.0.0';
const gradleVersion = '8.2.1'; const gradleVersion = '8.11.1';
const iOSVersion = '14';
let installFailed = false; let installFailed = false;
async function migrateCommand(config, noprompt, packagemanager) { async function migrateCommand(config, noprompt, packagemanager) {
if (config === null) { if (config === null) {
(0, errors_1.fatal)('Config data missing'); (0, errors_1.fatal)('Config data missing');
} }
const capMajor = await checkCapacitorMajorVersion(config); const capMajor = await checkCapacitorMajorVersion(config);
if (capMajor < 5) { if (capMajor < 6) {
(0, errors_1.fatal)('Migrate can only be used on capacitor 5 and above, please use the CLI in Capacitor 5 to upgrade to 5 first'); (0, errors_1.fatal)('Migrate can only be used on Capacitor 6, please use the CLI in Capacitor 6 to upgrade to 6 first');
} }
const jdkMajor = await (0, common_2.checkJDKMajorVersion)(); const jdkMajor = await (0, common_2.checkJDKMajorVersion)();
if (jdkMajor < 17) { if (jdkMajor < 21) {
log_1.logger.warn('Capacitor 6 requires JDK 17 or higher. Some steps may fail.'); log_1.logger.warn('Capacitor 7 requires JDK 21 or higher. Some steps may fail.');
} }
const variablesAndClasspaths = await getAndroidVariablesAndClasspaths(config); const variablesAndClasspaths = await getAndroidVariablesAndClasspaths(config);
if (!variablesAndClasspaths) { if (!variablesAndClasspaths) {
@ -78,14 +76,13 @@ async function migrateCommand(config, noprompt, packagemanager) {
log_1.logger.info(monorepoWarning); log_1.logger.info(monorepoWarning);
const { migrateconfirm } = noprompt const { migrateconfirm } = noprompt
? { migrateconfirm: 'y' } ? { migrateconfirm: 'y' }
: await (0, log_1.logPrompt)(`Capacitor 6 sets a deployment target of iOS 13 and Android 14 (SDK 34). \n`, { : await (0, log_1.logPrompt)(`Capacitor 7 sets a deployment target of iOS ${iOSVersion} and Android 15 (SDK 35). \n`, {
type: 'text', type: 'text',
name: 'migrateconfirm', name: 'migrateconfirm',
message: `Are you sure you want to migrate? (Y/n)`, message: `Are you sure you want to migrate? (Y/n)`,
initial: 'y', initial: 'y',
}); });
if (typeof migrateconfirm === 'string' && if (typeof migrateconfirm === 'string' && migrateconfirm.toLowerCase() === 'y') {
migrateconfirm.toLowerCase() === 'y') {
try { try {
const { depInstallConfirm } = noprompt const { depInstallConfirm } = noprompt
? { depInstallConfirm: 'y' } ? { depInstallConfirm: 'y' }
@ -95,8 +92,7 @@ async function migrateCommand(config, noprompt, packagemanager) {
message: `Run Dependency Install? (Y/n)`, message: `Run Dependency Install? (Y/n)`,
initial: 'y', initial: 'y',
}); });
const runNpmInstall = typeof depInstallConfirm === 'string' && const runNpmInstall = typeof depInstallConfirm === 'string' && depInstallConfirm.toLowerCase() === 'y';
depInstallConfirm.toLowerCase() === 'y';
let installerType = 'npm'; let installerType = 'npm';
if (runNpmInstall) { if (runNpmInstall) {
const { manager } = packagemanager const { manager } = packagemanager
@ -125,13 +121,23 @@ async function migrateCommand(config, noprompt, packagemanager) {
installFailed = true; installFailed = true;
} }
// Update iOS Projects // Update iOS Projects
if (allDependencies['@capacitor/ios'] && if (allDependencies['@capacitor/ios'] && (0, fs_extra_1.existsSync)(config.ios.platformDirAbs)) {
(0, utils_fs_1.existsSync)(config.ios.platformDirAbs)) { const currentiOSVersion = (0, common_3.getMajoriOSVersion)(config);
// ios template changes if (parseInt(currentiOSVersion) < parseInt(iOSVersion)) {
// Remove NSLocationAlwaysUsageDescription // ios template changes
await (0, common_2.runTask)(`Migrating Info.plist by removing NSLocationAlwaysUsageDescription key.`, () => { await (0, common_2.runTask)(`Migrating deployment target to ${iOSVersion}.0.`, () => {
return removeKey((0, path_1.join)(config.ios.nativeTargetDirAbs, 'Info.plist'), 'NSLocationAlwaysUsageDescription'); return updateFile(config, (0, path_1.join)(config.ios.nativeXcodeProjDirAbs, 'project.pbxproj'), 'IPHONEOS_DEPLOYMENT_TARGET = ', ';', `${iOSVersion}.0`);
}); });
if ((await (0, spm_1.checkPackageManager)(config)) === 'Cocoapods') {
// Update Podfile
await (0, common_2.runTask)(`Migrating Podfile to ${iOSVersion}.0.`, () => {
return updateFile(config, (0, path_1.join)(config.ios.nativeProjectDirAbs, 'Podfile'), `platform :ios, '`, `'`, `${iOSVersion}.0`);
});
}
}
else {
log_1.logger.warn('Skipped updating deployment target');
}
} }
if (!installFailed) { if (!installFailed) {
await (0, common_2.runTask)(`Running cap sync.`, () => { await (0, common_2.runTask)(`Running cap sync.`, () => {
@ -141,11 +147,18 @@ async function migrateCommand(config, noprompt, packagemanager) {
else { else {
log_1.logger.warn('Skipped Running cap sync.'); log_1.logger.warn('Skipped Running cap sync.');
} }
if (allDependencies['@capacitor/android'] && if (allDependencies['@capacitor/android'] && (0, fs_extra_1.existsSync)(config.android.platformDirAbs)) {
(0, utils_fs_1.existsSync)(config.android.platformDirAbs)) { // AndroidManifest.xml add navigation"
await (0, common_2.runTask)(`Migrating AndroidManifest.xml by adding navigation to Activity configChanges.`, () => {
return updateAndroidManifest((0, path_1.join)(config.android.srcMainDirAbs, 'AndroidManifest.xml'));
});
const gradleWrapperVersion = getGradleWrapperVersion((0, path_1.join)(config.android.platformDirAbs, 'gradle', 'wrapper', 'gradle-wrapper.properties')); const gradleWrapperVersion = getGradleWrapperVersion((0, path_1.join)(config.android.platformDirAbs, 'gradle', 'wrapper', 'gradle-wrapper.properties'));
if (!installFailed && (0, semver_1.gt)(gradleVersion, gradleWrapperVersion)) { if (!installFailed && (0, semver_1.gte)(gradleVersion, gradleWrapperVersion)) {
try { try {
await (0, common_2.runTask)(`Upgrading gradle wrapper`, () => {
return updateGradleWrapperFiles(config.android.platformDirAbs);
});
// Run twice as first time it only updates the wrapper properties file
await (0, common_2.runTask)(`Upgrading gradle wrapper files`, () => { await (0, common_2.runTask)(`Upgrading gradle wrapper files`, () => {
return updateGradleWrapperFiles(config.android.platformDirAbs); return updateGradleWrapperFiles(config.android.platformDirAbs);
}); });
@ -165,22 +178,6 @@ async function migrateCommand(config, noprompt, packagemanager) {
await (0, common_2.runTask)(`Migrating build.gradle file.`, () => { await (0, common_2.runTask)(`Migrating build.gradle file.`, () => {
return updateBuildGradle((0, path_1.join)(config.android.platformDirAbs, 'build.gradle'), variablesAndClasspaths); return updateBuildGradle((0, path_1.join)(config.android.platformDirAbs, 'build.gradle'), variablesAndClasspaths);
}); });
// Replace deprecated compileSdkVersion
await (0, common_2.runTask)('Replacing deprecated compileSdkVersion from build.gradle', () => {
return (async () => {
const buildGradleFilename = (0, path_1.join)(config.android.platformDirAbs, 'app', 'build.gradle');
const buildGradleText = readFile(buildGradleFilename);
if (!buildGradleText) {
log_1.logger.error(`Could not read ${buildGradleFilename}. Check its permissions and if it exists.`);
return;
}
const compileSdk = `compileSdkVersion rootProject.ext.compileSdkVersion`;
if (buildGradleText.includes(compileSdk)) {
const buildGradleReplaced = buildGradleText.replace(compileSdk, `compileSdk rootProject.ext.compileSdkVersion`);
(0, utils_fs_1.writeFileSync)(buildGradleFilename, buildGradleReplaced, 'utf-8');
}
})();
});
// Variables gradle // Variables gradle
await (0, common_2.runTask)(`Migrating variables.gradle file.`, () => { await (0, common_2.runTask)(`Migrating variables.gradle file.`, () => {
return (async () => { return (async () => {
@ -190,7 +187,7 @@ async function migrateCommand(config, noprompt, packagemanager) {
return; return;
} }
txt = txt.replace(/= {2}'/g, `= '`); txt = txt.replace(/= {2}'/g, `= '`);
(0, utils_fs_1.writeFileSync)(variablesPath, txt, { encoding: 'utf-8' }); (0, fs_extra_1.writeFileSync)(variablesPath, txt, { encoding: 'utf-8' });
for (const variable of Object.keys(variablesAndClasspaths.variables)) { for (const variable of Object.keys(variablesAndClasspaths.variables)) {
let replaceStart = `${variable} = '`; let replaceStart = `${variable} = '`;
let replaceEnd = `'\n`; let replaceEnd = `'\n`;
@ -201,11 +198,9 @@ async function migrateCommand(config, noprompt, packagemanager) {
if (txt.includes(replaceStart)) { if (txt.includes(replaceStart)) {
const first = txt.indexOf(replaceStart) + replaceStart.length; const first = txt.indexOf(replaceStart) + replaceStart.length;
const value = txt.substring(first, txt.indexOf(replaceEnd, first)); const value = txt.substring(first, txt.indexOf(replaceEnd, first));
if ((typeof variablesAndClasspaths.variables[variable] === if ((typeof variablesAndClasspaths.variables[variable] === 'number' &&
'number' &&
value <= variablesAndClasspaths.variables[variable]) || value <= variablesAndClasspaths.variables[variable]) ||
(typeof variablesAndClasspaths.variables[variable] === (typeof variablesAndClasspaths.variables[variable] === 'string' &&
'string' &&
(0, semver_1.lt)(value, variablesAndClasspaths.variables[variable]))) { (0, semver_1.lt)(value, variablesAndClasspaths.variables[variable]))) {
await updateFile(config, variablesPath, replaceStart, replaceEnd, variablesAndClasspaths.variables[variable].toString(), true); await updateFile(config, variablesPath, replaceStart, replaceEnd, variablesAndClasspaths.variables[variable].toString(), true);
} }
@ -214,16 +209,16 @@ async function migrateCommand(config, noprompt, packagemanager) {
let file = readFile(variablesPath); let file = readFile(variablesPath);
if (file) { if (file) {
file = file.replace('}', ` ${replaceStart}${variablesAndClasspaths.variables[variable].toString()}${replaceEnd}}`); file = file.replace('}', ` ${replaceStart}${variablesAndClasspaths.variables[variable].toString()}${replaceEnd}}`);
(0, utils_fs_1.writeFileSync)(variablesPath, file); (0, fs_extra_1.writeFileSync)(variablesPath, file);
} }
} }
} }
const pluginVariables = { const pluginVariables = {
firebaseMessagingVersion: '23.3.1', firebaseMessagingVersion: '24.1.0',
playServicesLocationVersion: '21.1.0', playServicesLocationVersion: '21.3.0',
androidxBrowserVersion: '1.7.0', androidxBrowserVersion: '1.8.0',
androidxMaterialVersion: '1.10.0', androidxMaterialVersion: '1.12.0',
androidxExifInterfaceVersion: '1.3.6', androidxExifInterfaceVersion: '1.3.7',
androidxCoreKTXVersion: '1.12.0', androidxCoreKTXVersion: '1.12.0',
googleMapsPlayServicesVersion: '18.2.0', googleMapsPlayServicesVersion: '18.2.0',
googleMapsUtilsVersion: '3.8.2', googleMapsUtilsVersion: '3.8.2',
@ -237,7 +232,7 @@ async function migrateCommand(config, noprompt, packagemanager) {
} }
})(); })();
}); });
rimraf_1.default.sync((0, path_1.join)(config.android.appDirAbs, 'build')); rimraf_1.rimraf.sync((0, path_1.join)(config.android.appDirAbs, 'build'));
if (!installFailed) { if (!installFailed) {
await (0, common_2.runTask)('Migrating package from Manifest to build.gradle in Capacitor plugins', () => { await (0, common_2.runTask)('Migrating package from Manifest to build.gradle in Capacitor plugins', () => {
return patchOldCapacitorPlugins(config); return patchOldCapacitorPlugins(config);
@ -297,11 +292,11 @@ async function installLatestLibs(dependencyManager, runInstall, config) {
pkgJson['dependencies'][depKey] = pluginVersion; pkgJson['dependencies'][depKey] = pluginVersion;
} }
} }
(0, utils_fs_1.writeFileSync)(pkgJsonPath, JSON.stringify(pkgJson, null, 2), { (0, fs_extra_1.writeFileSync)(pkgJsonPath, JSON.stringify(pkgJson, null, 2), {
encoding: 'utf-8', encoding: 'utf-8',
}); });
if (runInstall) { if (runInstall) {
rimraf_1.default.sync((0, path_1.join)(config.app.rootDir, 'node_modules/@capacitor/!(cli)')); rimraf_1.rimraf.sync((0, path_1.join)(config.app.rootDir, 'node_modules/@capacitor/!(cli)'));
await (0, subprocess_1.runCommand)(dependencyManager, ['install']); await (0, subprocess_1.runCommand)(dependencyManager, ['install']);
if (dependencyManager == 'yarn') { if (dependencyManager == 'yarn') {
await (0, subprocess_1.runCommand)(dependencyManager, ['upgrade']); await (0, subprocess_1.runCommand)(dependencyManager, ['upgrade']);
@ -316,11 +311,11 @@ async function installLatestLibs(dependencyManager, runInstall, config) {
} }
async function writeBreakingChanges() { async function writeBreakingChanges() {
const breaking = [ const breaking = [
'@capacitor/camera', '@capacitor/app',
'@capacitor/filesystem', '@capacitor/device',
'@capacitor/geolocation', '@capacitor/haptics',
'@capacitor/google-maps', '@capacitor/splash-screen',
'@capacitor/local-notifications', '@capacitor/statusbar',
]; ];
const broken = []; const broken = [];
for (const lib of breaking) { for (const lib of breaking) {
@ -329,7 +324,7 @@ async function writeBreakingChanges() {
} }
} }
if (broken.length > 0) { if (broken.length > 0) {
log_1.logger.info(`IMPORTANT: Review https://capacitorjs.com/docs/next/updating/6-0#plugins for breaking changes in these plugins that you use: ${broken.join(', ')}.`); log_1.logger.info(`IMPORTANT: Review https://capacitorjs.com/docs/next/updating/7-0#plugins for breaking changes in these plugins that you use: ${broken.join(', ')}.`);
} }
} }
async function getAndroidVariablesAndClasspaths(config) { async function getAndroidVariablesAndClasspaths(config) {
@ -343,10 +338,8 @@ async function getAndroidVariablesAndClasspaths(config) {
(0, fs_1.deleteFolderRecursive)(tempAndroidTemplateFolder); (0, fs_1.deleteFolderRecursive)(tempAndroidTemplateFolder);
const firstIndxOfCATBGV = buildGradleFile.indexOf(`classpath 'com.android.tools.build:gradle:`) + 42; const firstIndxOfCATBGV = buildGradleFile.indexOf(`classpath 'com.android.tools.build:gradle:`) + 42;
const firstIndxOfCGGGS = buildGradleFile.indexOf(`com.google.gms:google-services:`) + 31; const firstIndxOfCGGGS = buildGradleFile.indexOf(`com.google.gms:google-services:`) + 31;
const comAndroidToolsBuildGradleVersion = '' + const comAndroidToolsBuildGradleVersion = '' + buildGradleFile.substring(firstIndxOfCATBGV, buildGradleFile.indexOf("'", firstIndxOfCATBGV));
buildGradleFile.substring(firstIndxOfCATBGV, buildGradleFile.indexOf("'", firstIndxOfCATBGV)); const comGoogleGmsGoogleServices = '' + buildGradleFile.substring(firstIndxOfCGGGS, buildGradleFile.indexOf("'", firstIndxOfCGGGS));
const comGoogleGmsGoogleServices = '' +
buildGradleFile.substring(firstIndxOfCGGGS, buildGradleFile.indexOf("'", firstIndxOfCGGGS));
const variablesGradleAsJSON = JSON.parse(variablesGradleFile const variablesGradleAsJSON = JSON.parse(variablesGradleFile
.replace('ext ', '') .replace('ext ', '')
.replace(/=/g, ':') .replace(/=/g, ':')
@ -359,18 +352,18 @@ async function getAndroidVariablesAndClasspaths(config) {
.replace(/\s/g, '') .replace(/\s/g, '')
.replace(/'/g, '"')); .replace(/'/g, '"'));
return { return {
'variables': variablesGradleAsJSON, variables: variablesGradleAsJSON,
'com.android.tools.build:gradle': comAndroidToolsBuildGradleVersion, 'com.android.tools.build:gradle': comAndroidToolsBuildGradleVersion,
'com.google.gms:google-services': comGoogleGmsGoogleServices, 'com.google.gms:google-services': comGoogleGmsGoogleServices,
}; };
} }
function readFile(filename) { function readFile(filename) {
try { try {
if (!(0, utils_fs_1.existsSync)(filename)) { if (!(0, fs_extra_1.existsSync)(filename)) {
log_1.logger.error(`Unable to find ${filename}. Try updating it manually`); log_1.logger.error(`Unable to find ${filename}. Try updating it manually`);
return; return;
} }
return (0, utils_fs_1.readFileSync)(filename, 'utf-8'); return (0, fs_extra_1.readFileSync)(filename, 'utf-8');
} }
catch (err) { catch (err) {
log_1.logger.error(`Unable to read ${filename}. Verify it is not already open. ${err}`); log_1.logger.error(`Unable to read ${filename}. Verify it is not already open. ${err}`);
@ -387,15 +380,7 @@ function getGradleWrapperVersion(filename) {
return semverVersion ? semverVersion : '0.0.0'; return semverVersion ? semverVersion : '0.0.0';
} }
async function updateGradleWrapperFiles(platformDir) { async function updateGradleWrapperFiles(platformDir) {
await (0, subprocess_1.runCommand)(`./gradlew`, [ await (0, subprocess_1.runCommand)(`./gradlew`, ['wrapper', '--distribution-type', 'all', '--gradle-version', gradleVersion, '--warning-mode', 'all'], {
'wrapper',
'--distribution-type',
'all',
'--gradle-version',
gradleVersion,
'--warning-mode',
'all',
], {
cwd: platformDir, cwd: platformDir,
}); });
} }
@ -437,8 +422,8 @@ async function movePackageFromManifestToBuildGradle(manifestFilename, buildGradl
log_1.logger.error(`Unable to update buildGradleText: no changes were detected in Android Manifest file`); log_1.logger.error(`Unable to update buildGradleText: no changes were detected in Android Manifest file`);
return; return;
} }
(0, utils_fs_1.writeFileSync)(manifestFilename, manifestReplaced, 'utf-8'); (0, fs_extra_1.writeFileSync)(manifestFilename, manifestReplaced, 'utf-8');
(0, utils_fs_1.writeFileSync)(buildGradleFilename, buildGradleReplaced, 'utf-8'); (0, fs_extra_1.writeFileSync)(buildGradleFilename, buildGradleReplaced, 'utf-8');
} }
async function updateBuildGradle(filename, variablesAndClasspaths) { async function updateBuildGradle(filename, variablesAndClasspaths) {
const txt = readFile(filename); const txt = readFile(filename);
@ -460,7 +445,7 @@ async function updateBuildGradle(filename, variablesAndClasspaths) {
} }
} }
} }
(0, utils_fs_1.writeFileSync)(filename, replaced, 'utf-8'); (0, fs_extra_1.writeFileSync)(filename, replaced, 'utf-8');
} }
async function updateFile(config, filename, textStart, textEnd, replacement, skipIfNotFound) { async function updateFile(config, filename, textStart, textEnd, replacement, skipIfNotFound) {
if (config === null) { if (config === null) {
@ -474,7 +459,7 @@ async function updateFile(config, filename, textStart, textEnd, replacement, ski
if (txt.includes(textStart)) { if (txt.includes(textStart)) {
if (replacement) { if (replacement) {
txt = setAllStringIn(txt, textStart, textEnd, replacement); txt = setAllStringIn(txt, textStart, textEnd, replacement);
(0, utils_fs_1.writeFileSync)(path, txt, { encoding: 'utf-8' }); (0, fs_extra_1.writeFileSync)(path, txt, { encoding: 'utf-8' });
} }
else { else {
// Replacing in code so we need to count the number of brackets to find the end of the function in swift // Replacing in code so we need to count the number of brackets to find the end of the function in swift
@ -497,7 +482,7 @@ async function updateFile(config, filename, textStart, textEnd, replacement, ski
replaced += line + '\n'; replaced += line + '\n';
} }
} }
(0, utils_fs_1.writeFileSync)(path, replaced, { encoding: 'utf-8' }); (0, fs_extra_1.writeFileSync)(path, replaced, { encoding: 'utf-8' });
} }
return true; return true;
} }
@ -518,14 +503,22 @@ function setAllStringIn(data, start, end, replacement) {
else { else {
const idx = foundIdx + start.length; const idx = foundIdx + start.length;
position = idx + replacement.length; position = idx + replacement.length;
result = result = result.substring(0, idx) + replacement + result.substring(result.indexOf(end, idx));
result.substring(0, idx) +
replacement +
result.substring(result.indexOf(end, idx));
} }
} }
return result; return result;
} }
async function updateAndroidManifest(filename) {
const txt = readFile(filename);
if (!txt) {
return;
}
if (txt.includes('navigation')) {
return; // Probably already updated
}
const replaced = txt.replace('android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"', 'android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation"');
(0, fs_extra_1.writeFileSync)(filename, replaced, 'utf-8');
}
async function patchOldCapacitorPlugins(config) { async function patchOldCapacitorPlugins(config) {
const allPlugins = await (0, plugin_1.getPlugins)(config, 'android'); const allPlugins = await (0, plugin_1.getPlugins)(config, 'android');
const androidPlugins = await (0, common_1.getAndroidPlugins)(allPlugins); const androidPlugins = await (0, common_1.getAndroidPlugins)(allPlugins);
@ -550,26 +543,3 @@ async function patchOldCapacitorPlugins(config) {
})); }));
} }
exports.patchOldCapacitorPlugins = patchOldCapacitorPlugins; exports.patchOldCapacitorPlugins = patchOldCapacitorPlugins;
async function removeKey(filename, key) {
const txt = readFile(filename);
if (!txt) {
return;
}
let lines = txt.split('\n');
let removed = false;
let removing = false;
lines = lines.filter(line => {
if (removing && line.includes('</string>')) {
removing = false;
return false;
}
if (line.includes(`<key>${key}</key`)) {
removing = true;
removed = true;
}
return !removing;
});
if (removed) {
(0, utils_fs_1.writeFileSync)(filename, lines.join('\n'), 'utf-8');
}
}

View file

@ -5,7 +5,6 @@ const tslib_1 = require("tslib");
const colors_1 = tslib_1.__importDefault(require("../colors")); const colors_1 = tslib_1.__importDefault(require("../colors"));
const errors_1 = require("../errors"); const errors_1 = require("../errors");
async function newPluginCommand() { async function newPluginCommand() {
(0, errors_1.fatal)(`The plugin:generate command has been removed.\n` + (0, errors_1.fatal)(`The plugin:generate command has been removed.\n` + `Use ${colors_1.default.input('npm init @capacitor/plugin')}`);
`Use ${colors_1.default.input('npm init @capacitor/plugin')}`);
} }
exports.newPluginCommand = newPluginCommand; exports.newPluginCommand = newPluginCommand;

View file

@ -41,7 +41,7 @@ async function openCommand(config, selectedPlatformName) {
} }
exports.openCommand = openCommand; exports.openCommand = openCommand;
function createOpenablePlatformFilter(config) { function createOpenablePlatformFilter(config) {
return platform => platform === config.ios.name || platform === config.android.name; return (platform) => platform === config.ios.name || platform === config.android.name;
} }
async function open(config, platformName) { async function open(config, platformName) {
if (platformName === config.ios.name) { if (platformName === config.ios.name) {

View file

@ -2,7 +2,6 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.run = exports.runCommand = void 0; exports.run = exports.runCommand = void 0;
const tslib_1 = require("tslib"); const tslib_1 = require("tslib");
const utils_process_1 = require("@ionic/utils-process");
const utils_terminal_1 = require("@ionic/utils-terminal"); const utils_terminal_1 = require("@ionic/utils-terminal");
const run_1 = require("../android/run"); const run_1 = require("../android/run");
const colors_1 = tslib_1.__importDefault(require("../colors")); const colors_1 = tslib_1.__importDefault(require("../colors"));
@ -16,8 +15,7 @@ const native_run_1 = require("../util/native-run");
const sync_1 = require("./sync"); const sync_1 = require("./sync");
async function runCommand(config, selectedPlatformName, options) { async function runCommand(config, selectedPlatformName, options) {
var _a, _b, _c, _d; var _a, _b, _c, _d;
options.host = options.host = (_b = (_a = options.host) !== null && _a !== void 0 ? _a : livereload_1.CapLiveReloadHelper.getIpAddress()) !== null && _b !== void 0 ? _b : 'localhost';
(_b = (_a = options.host) !== null && _a !== void 0 ? _a : livereload_1.CapLiveReloadHelper.getIpAddress()) !== null && _b !== void 0 ? _b : 'localhost';
options.port = (_c = options.port) !== null && _c !== void 0 ? _c : '3000'; options.port = (_c = options.port) !== null && _c !== void 0 ? _c : '3000';
if (selectedPlatformName && !(await (0, common_1.isValidPlatform)(selectedPlatformName))) { if (selectedPlatformName && !(await (0, common_1.isValidPlatform)(selectedPlatformName))) {
const platformDir = (0, common_1.resolvePlatform)(config, selectedPlatformName); const platformDir = (0, common_1.resolvePlatform)(config, selectedPlatformName);
@ -39,7 +37,7 @@ async function runCommand(config, selectedPlatformName, options) {
} }
if (options.list) { if (options.list) {
const targets = await (0, native_run_1.getPlatformTargets)(platformName); const targets = await (0, native_run_1.getPlatformTargets)(platformName);
const outputTargets = targets.map(t => { const outputTargets = targets.map((t) => {
var _a; var _a;
return ({ return ({
name: (0, common_1.getPlatformTargetName)(t), name: (0, common_1.getPlatformTargetName)(t),
@ -47,12 +45,11 @@ async function runCommand(config, selectedPlatformName, options) {
id: (_a = t.id) !== null && _a !== void 0 ? _a : '?', id: (_a = t.id) !== null && _a !== void 0 ? _a : '?',
}); });
}); });
// TODO: make hidden commander option (https://github.com/tj/commander.js/issues/1106) if (options.json) {
if (process.argv.includes('--json')) {
process.stdout.write(`${JSON.stringify(outputTargets)}\n`); process.stdout.write(`${JSON.stringify(outputTargets)}\n`);
} }
else { else {
const rows = outputTargets.map(t => [t.name, t.api, t.id]); const rows = outputTargets.map((t) => [t.name, t.api, t.id]);
log_1.output.write(`${(0, utils_terminal_1.columnar)(rows, { log_1.output.write(`${(0, utils_terminal_1.columnar)(rows, {
headers: ['Name', 'API', 'Target ID'], headers: ['Name', 'API', 'Target ID'],
vsep: ' ', vsep: ' ',
@ -73,7 +70,7 @@ async function runCommand(config, selectedPlatformName, options) {
} }
await run(config, platformName, options); await run(config, platformName, options);
if (options.liveReload) { if (options.liveReload) {
new Promise(resolve => process.on('SIGINT', resolve)) new Promise((resolve) => process.on('SIGINT', resolve))
.then(async () => { .then(async () => {
await livereload_1.CapLiveReloadHelper.revertCapConfigForLiveReload(); await livereload_1.CapLiveReloadHelper.revertCapConfigForLiveReload();
if (platformName === config.android.name) { if (platformName === config.android.name) {
@ -82,7 +79,7 @@ async function runCommand(config, selectedPlatformName, options) {
}) })
.then(() => process.exit()); .then(() => process.exit());
log_1.logger.info(`App running with live reload listing for: http://${options.host}:${options.port}. Press Ctrl+C to quit.`); log_1.logger.info(`App running with live reload listing for: http://${options.host}:${options.port}. Press Ctrl+C to quit.`);
await (0, utils_process_1.sleepForever)(); await sleepForever();
} }
} }
catch (e) { catch (e) {
@ -110,5 +107,12 @@ async function run(config, platformName, options) {
} }
exports.run = run; exports.run = run;
function createRunnablePlatformFilter(config) { function createRunnablePlatformFilter(config) {
return platform => platform === config.ios.name || platform === config.android.name; return (platform) => platform === config.ios.name || platform === config.android.name;
}
async function sleepForever() {
return new Promise(() => {
setInterval(() => {
/* do nothing */
}, 1000);
});
} }

View file

@ -1,25 +1,24 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.inlineSourceMaps = void 0; exports.inlineSourceMaps = void 0;
const utils_fs_1 = require("@ionic/utils-fs"); const fs_extra_1 = require("fs-extra");
const path_1 = require("path"); const path_1 = require("path");
const log_1 = require("../log"); const log_1 = require("../log");
function walkDirectory(dirPath) { function walkDirectory(dirPath) {
const files = (0, utils_fs_1.readdirSync)(dirPath); const files = (0, fs_extra_1.readdirSync)(dirPath);
files.forEach(file => { files.forEach((file) => {
const targetFile = (0, path_1.join)(dirPath, file); const targetFile = (0, path_1.join)(dirPath, file);
if ((0, utils_fs_1.existsSync)(targetFile) && (0, utils_fs_1.lstatSync)(targetFile).isDirectory()) { if ((0, fs_extra_1.existsSync)(targetFile) && (0, fs_extra_1.lstatSync)(targetFile).isDirectory()) {
walkDirectory(targetFile); walkDirectory(targetFile);
} }
else { else {
const mapFile = (0, path_1.join)(dirPath, `${file}.map`); const mapFile = (0, path_1.join)(dirPath, `${file}.map`);
if ((0, path_1.extname)(file) === '.js' && (0, utils_fs_1.existsSync)(mapFile)) { if ((0, path_1.extname)(file) === '.js' && (0, fs_extra_1.existsSync)(mapFile)) {
const bufMap = (0, utils_fs_1.readFileSync)(mapFile).toString('base64'); const bufMap = (0, fs_extra_1.readFileSync)(mapFile).toString('base64');
const bufFile = (0, utils_fs_1.readFileSync)(targetFile, 'utf8'); const bufFile = (0, fs_extra_1.readFileSync)(targetFile, 'utf8');
const result = bufFile.replace(`sourceMappingURL=${file}.map`, 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + const result = bufFile.replace(`sourceMappingURL=${file}.map`, 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + bufMap);
bufMap); (0, fs_extra_1.writeFileSync)(targetFile, result);
(0, utils_fs_1.writeFileSync)(targetFile, result); (0, fs_extra_1.unlinkSync)(mapFile);
(0, utils_fs_1.unlinkSync)(mapFile);
} }
} }
}); });

View file

@ -25,12 +25,8 @@ async function syncCommand(config, selectedPlatformName, deployment, inline = fa
const then = +new Date(); const then = +new Date();
const platforms = await (0, common_1.selectPlatforms)(config, selectedPlatformName); const platforms = await (0, common_1.selectPlatforms)(config, selectedPlatformName);
try { try {
await (0, common_1.check)([ await (0, common_1.check)([() => (0, common_1.checkPackage)(), () => (0, common_1.checkWebDir)(config), ...(0, update_1.updateChecks)(config, platforms)]);
() => (0, common_1.checkPackage)(), await (0, promise_1.allSerial)(platforms.map((platformName) => () => sync(config, platformName, deployment, inline)));
() => (0, common_1.checkWebDir)(config),
...(0, update_1.updateChecks)(config, platforms),
]);
await (0, promise_1.allSerial)(platforms.map(platformName => () => sync(config, platformName, deployment, inline)));
const now = +new Date(); const now = +new Date();
const diff = (now - then) / 1000; const diff = (now - then) / 1000;
log_1.logger.info(`Sync finished in ${diff}s`); log_1.logger.info(`Sync finished in ${diff}s`);

View file

@ -6,7 +6,8 @@ const colors_1 = tslib_1.__importDefault(require("../colors"));
const errors_1 = require("../errors"); const errors_1 = require("../errors");
const log_1 = require("../log"); const log_1 = require("../log");
const sysconfig_1 = require("../sysconfig"); const sysconfig_1 = require("../sysconfig");
const telemetry_1 = require("../telemetry"); const THANK_YOU = `\nThank you for helping to make Capacitor better! 💖` +
`\nInformation about the data we collect is available on our website: ${colors_1.default.strong('https://capacitorjs.com/docs/next/cli/telemetry')}\n`;
async function telemetryCommand(onOrOff) { async function telemetryCommand(onOrOff) {
const sysconfig = await (0, sysconfig_1.readConfig)(); const sysconfig = await (0, sysconfig_1.readConfig)();
const enabled = interpretEnabled(onOrOff); const enabled = interpretEnabled(onOrOff);
@ -18,7 +19,7 @@ async function telemetryCommand(onOrOff) {
await (0, sysconfig_1.writeConfig)({ ...sysconfig, telemetry: enabled }); await (0, sysconfig_1.writeConfig)({ ...sysconfig, telemetry: enabled });
(0, log_1.logSuccess)(`You have ${colors_1.default.strong(`opted ${enabled ? 'in' : 'out'}`)} ${enabled ? 'for' : 'of'} telemetry on this machine.`); (0, log_1.logSuccess)(`You have ${colors_1.default.strong(`opted ${enabled ? 'in' : 'out'}`)} ${enabled ? 'for' : 'of'} telemetry on this machine.`);
if (enabled) { if (enabled) {
log_1.output.write(telemetry_1.THANK_YOU); log_1.output.write(THANK_YOU);
} }
} }
} }

View file

@ -26,7 +26,7 @@ async function updateCommand(config, selectedPlatformName, deployment) {
const platforms = await (0, common_1.selectPlatforms)(config, selectedPlatformName); const platforms = await (0, common_1.selectPlatforms)(config, selectedPlatformName);
try { try {
await (0, common_1.check)([() => (0, common_1.checkPackage)(), ...updateChecks(config, platforms)]); await (0, common_1.check)([() => (0, common_1.checkPackage)(), ...updateChecks(config, platforms)]);
await (0, promise_1.allSerial)(platforms.map(platformName => async () => await update(config, platformName, deployment))); await (0, promise_1.allSerial)(platforms.map((platformName) => async () => await update(config, platformName, deployment)));
const now = +new Date(); const now = +new Date();
const diff = (now - then) / 1000; const diff = (now - then) / 1000;
log_1.logger.info(`Update finished in ${diff}s`); log_1.logger.info(`Update finished in ${diff}s`);

View file

@ -1,6 +1,6 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.sendMetric = exports.telemetryAction = exports.THANK_YOU = void 0; exports.sendMetric = exports.telemetryAction = void 0;
const tslib_1 = require("tslib"); const tslib_1 = require("tslib");
const commander_1 = require("commander"); const commander_1 = require("commander");
const debug_1 = tslib_1.__importDefault(require("debug")); const debug_1 = tslib_1.__importDefault(require("debug"));
@ -11,8 +11,9 @@ const sysconfig_1 = require("./sysconfig");
const subprocess_1 = require("./util/subprocess"); const subprocess_1 = require("./util/subprocess");
const term_1 = require("./util/term"); const term_1 = require("./util/term");
const debug = (0, debug_1.default)('capacitor:telemetry'); const debug = (0, debug_1.default)('capacitor:telemetry');
exports.THANK_YOU = `\nThank you for helping to make Capacitor better! 💖` + const THANK_YOU = `\nThank you for helping improve Capacitor by sharing anonymous usage data! 💖` +
`\nInformation about the data we collect is available on our website: ${colors_1.default.strong('https://capacitorjs.com/telemetry')}\n`; `\nInformation about the data we collect is available on our website: ${colors_1.default.strong('https://capacitorjs.com/docs/next/cli/telemetry')}` +
`\nYou can disable telemetry at any time by using the ${colors_1.default.input('npx cap telemetry off')} command.`;
function telemetryAction(config, action) { function telemetryAction(config, action) {
return async (...actionArgs) => { return async (...actionArgs) => {
const start = new Date(); const start = new Date();
@ -55,9 +56,10 @@ function telemetryAction(config, action) {
if ((0, term_1.isInteractive)()) { if ((0, term_1.isInteractive)()) {
let sysconfig = await (0, sysconfig_1.readConfig)(); let sysconfig = await (0, sysconfig_1.readConfig)();
if (!error && typeof sysconfig.telemetry === 'undefined') { if (!error && typeof sysconfig.telemetry === 'undefined') {
const confirm = await promptForTelemetry(); // Telemetry is opt-out; turn telemetry on then inform the user how to opt-out.
sysconfig = { ...sysconfig, telemetry: confirm }; sysconfig = { ...sysconfig, telemetry: true };
await (0, sysconfig_1.writeConfig)(sysconfig); await (0, sysconfig_1.writeConfig)(sysconfig);
log_1.output.write(THANK_YOU);
} }
await sendMetric(sysconfig, 'capacitor_cli_command', data); await sendMetric(sysconfig, 'capacitor_cli_command', data);
} }
@ -86,19 +88,6 @@ async function sendMetric(sysconfig, name, data) {
} }
} }
exports.sendMetric = sendMetric; exports.sendMetric = sendMetric;
async function promptForTelemetry() {
const { confirm } = await (0, log_1.logPrompt)(`${colors_1.default.strong('Would you like to help improve Capacitor by sharing anonymous usage data? 💖')}\n` +
`Read more about what is being collected and why here: ${colors_1.default.strong('https://capacitorjs.com/telemetry')}. You can change your mind at any time by using the ${colors_1.default.input('npx cap telemetry')} command.`, {
type: 'confirm',
name: 'confirm',
message: 'Share anonymous usage data?',
initial: true,
});
if (confirm) {
log_1.output.write(exports.THANK_YOU);
}
return confirm;
}
/** /**
* Get a unique anonymous identifier for this app. * Get a unique anonymous identifier for this app.
*/ */

View file

@ -1,24 +1,43 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.deleteFolderRecursive = exports.convertToUnixPath = void 0; exports.readdirp = exports.deleteFolderRecursive = exports.convertToUnixPath = void 0;
const utils_fs_1 = require("@ionic/utils-fs"); const fs_1 = require("fs");
const promises_1 = require("fs/promises");
const fs_extra_1 = require("fs-extra");
const path_1 = require("path"); const path_1 = require("path");
const convertToUnixPath = (path) => { const convertToUnixPath = (path) => {
return path.replace(/\\/g, '/'); return path.replace(/\\/g, '/');
}; };
exports.convertToUnixPath = convertToUnixPath; exports.convertToUnixPath = convertToUnixPath;
const deleteFolderRecursive = (directoryPath) => { const deleteFolderRecursive = (directoryPath) => {
if ((0, utils_fs_1.existsSync)(directoryPath)) { if ((0, fs_extra_1.existsSync)(directoryPath)) {
(0, utils_fs_1.readdirSync)(directoryPath).forEach(file => { (0, fs_extra_1.readdirSync)(directoryPath).forEach((file) => {
const curPath = (0, path_1.join)(directoryPath, file); const curPath = (0, path_1.join)(directoryPath, file);
if ((0, utils_fs_1.lstatSync)(curPath).isDirectory()) { if ((0, fs_extra_1.lstatSync)(curPath).isDirectory()) {
(0, exports.deleteFolderRecursive)(curPath); (0, exports.deleteFolderRecursive)(curPath);
} }
else { else {
(0, utils_fs_1.unlinkSync)(curPath); (0, fs_extra_1.unlinkSync)(curPath);
} }
}); });
(0, utils_fs_1.rmdirSync)(directoryPath); (0, fs_extra_1.rmdirSync)(directoryPath);
} }
}; };
exports.deleteFolderRecursive = deleteFolderRecursive; exports.deleteFolderRecursive = deleteFolderRecursive;
async function readdirp(dir, { filter }) {
const dirContent = await (0, promises_1.readdir)(dir, { recursive: true });
const dirContentWalker = [];
const filteredContent = [];
dirContent.forEach((element) => {
const path = (0, path_1.join)(dir, element);
const stats = (0, fs_1.statSync)(path);
dirContentWalker.push({ path, stats });
});
dirContentWalker.forEach((element) => {
if (filter(element)) {
filteredContent.push(element.path);
}
});
return filteredContent;
}
exports.readdirp = readdirp;

View file

@ -1,17 +1,17 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.generateIOSPackageJSON = exports.writePluginJSON = exports.findPluginClasses = exports.getPluginFiles = void 0; exports.generateIOSPackageJSON = exports.writePluginJSON = exports.findPluginClasses = exports.getPluginFiles = void 0;
const utils_fs_1 = require("@ionic/utils-fs"); const fs_extra_1 = require("fs-extra");
const path_1 = require("path"); const path_1 = require("path");
const cordova_1 = require("../cordova"); const cordova_1 = require("../cordova");
const plugin_1 = require("../plugin"); const plugin_1 = require("../plugin");
const fs_1 = require("./fs");
async function getPluginFiles(plugins) { async function getPluginFiles(plugins) {
var _a; var _a;
let filenameList = []; let filenameList = [];
const options = { const options = {
filter: item => { filter: (item) => {
if (item.stats.isFile() && if (item.stats.isFile() && (item.path.endsWith('.swift') || item.path.endsWith('.m'))) {
(item.path.endsWith('.swift') || item.path.endsWith('.m'))) {
return true; return true;
} }
else { else {
@ -22,7 +22,7 @@ async function getPluginFiles(plugins) {
for (const plugin of plugins) { for (const plugin of plugins) {
if (plugin.ios && (0, plugin_1.getPluginType)(plugin, 'ios') === 0 /* PluginType.Core */) { if (plugin.ios && (0, plugin_1.getPluginType)(plugin, 'ios') === 0 /* PluginType.Core */) {
const pluginPath = (0, path_1.resolve)(plugin.rootPath, (_a = plugin.ios) === null || _a === void 0 ? void 0 : _a.path); const pluginPath = (0, path_1.resolve)(plugin.rootPath, (_a = plugin.ios) === null || _a === void 0 ? void 0 : _a.path);
const filenames = await (0, utils_fs_1.readdirp)(pluginPath, options); const filenames = await (0, fs_1.readdirp)(pluginPath, options);
filenameList = filenameList.concat(filenames); filenameList = filenameList.concat(filenames);
} }
} }
@ -32,7 +32,7 @@ exports.getPluginFiles = getPluginFiles;
async function findPluginClasses(files) { async function findPluginClasses(files) {
const classList = []; const classList = [];
for (const file of files) { for (const file of files) {
const fileData = (0, utils_fs_1.readFileSync)(file, 'utf-8'); const fileData = (0, fs_extra_1.readFileSync)(file, 'utf-8');
const swiftPluginRegex = RegExp(/@objc\(([A-Za-z0-9_-]+)\)/); const swiftPluginRegex = RegExp(/@objc\(([A-Za-z0-9_-]+)\)/);
const objcPluginRegex = RegExp(/CAP_PLUGIN\(([A-Za-z0-9_-]+)/); const objcPluginRegex = RegExp(/CAP_PLUGIN\(([A-Za-z0-9_-]+)/);
const swiftMatches = swiftPluginRegex.exec(fileData); const swiftMatches = swiftPluginRegex.exec(fileData);
@ -49,9 +49,9 @@ async function findPluginClasses(files) {
exports.findPluginClasses = findPluginClasses; exports.findPluginClasses = findPluginClasses;
async function writePluginJSON(config, classList) { async function writePluginJSON(config, classList) {
const capJSONFile = (0, path_1.resolve)(config.ios.nativeTargetDirAbs, 'capacitor.config.json'); const capJSONFile = (0, path_1.resolve)(config.ios.nativeTargetDirAbs, 'capacitor.config.json');
const capJSON = (0, utils_fs_1.readJSONSync)(capJSONFile); const capJSON = (0, fs_extra_1.readJSONSync)(capJSONFile);
capJSON['packageClassList'] = classList; capJSON['packageClassList'] = classList;
(0, utils_fs_1.writeJSONSync)(capJSONFile, capJSON, { spaces: '\t' }); (0, fs_extra_1.writeJSONSync)(capJSONFile, capJSON, { spaces: '\t' });
} }
exports.writePluginJSON = writePluginJSON; exports.writePluginJSON = writePluginJSON;
async function generateIOSPackageJSON(config, plugins) { async function generateIOSPackageJSON(config, plugins) {

View file

@ -1,7 +1,7 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.CapLiveReloadHelper = void 0; exports.CapLiveReloadHelper = void 0;
const utils_fs_1 = require("@ionic/utils-fs"); const fs_extra_1 = require("fs-extra");
const os_1 = require("os"); const os_1 = require("os");
const path_1 = require("path"); const path_1 = require("path");
class CapLiveReload { class CapLiveReload {
@ -73,7 +73,7 @@ class CapLiveReload {
return res[0].address; return res[0].address;
} }
const all = Object.keys(interfaces) const all = Object.keys(interfaces)
.map(nic => { .map((nic) => {
// //
// Note: name will only be `public` or `private` // Note: name will only be `public` or `private`
// when this is called. // when this is called.
@ -86,9 +86,7 @@ class CapLiveReload {
if (!name) { if (!name) {
return true; return true;
} }
return name === 'public' return name === 'public' ? isPrivate(details.address) : isPublic(details.address);
? isPrivate(details.address)
: isPublic(details.address);
}); });
return addresses.length ? addresses[0].address : undefined; return addresses.length ? addresses[0].address : undefined;
}) })
@ -128,22 +126,21 @@ class CapLiveReload {
const capConfigPath = rootConfigChange const capConfigPath = rootConfigChange
? config.app.extConfigFilePath ? config.app.extConfigFilePath
: (0, path_1.join)(platformAbsPath, 'capacitor.config.json'); : (0, path_1.join)(platformAbsPath, 'capacitor.config.json');
const configJson = (0, utils_fs_1.readJSONSync)(capConfigPath); const configJson = (0, fs_extra_1.readJSONSync)(capConfigPath);
this.configJsonToRevertTo.json = JSON.stringify(configJson, null, 2); this.configJsonToRevertTo.json = JSON.stringify(configJson, null, 2);
this.configJsonToRevertTo.platformPath = capConfigPath; this.configJsonToRevertTo.platformPath = capConfigPath;
const url = `http://${options.host}:${options.port}`; const url = `http://${options.host}:${options.port}`;
configJson.server = { configJson.server = {
url, url,
}; };
(0, utils_fs_1.writeJSONSync)(capConfigPath, configJson, { spaces: '\t' }); (0, fs_extra_1.writeJSONSync)(capConfigPath, configJson, { spaces: '\t' });
} }
async revertCapConfigForLiveReload() { async revertCapConfigForLiveReload() {
if (this.configJsonToRevertTo.json == null || if (this.configJsonToRevertTo.json == null || this.configJsonToRevertTo.platformPath == null)
this.configJsonToRevertTo.platformPath == null)
return; return;
const capConfigPath = this.configJsonToRevertTo.platformPath; const capConfigPath = this.configJsonToRevertTo.platformPath;
const configJson = this.configJsonToRevertTo.json; const configJson = this.configJsonToRevertTo.json;
(0, utils_fs_1.writeJSONSync)(capConfigPath, JSON.parse(configJson), { spaces: '\t' }); (0, fs_extra_1.writeJSONSync)(capConfigPath, JSON.parse(configJson), { spaces: '\t' });
this.configJsonToRevertTo.json = null; this.configJsonToRevertTo.json = null;
this.configJsonToRevertTo.platformPath = null; this.configJsonToRevertTo.platformPath = null;
} }

View file

@ -13,8 +13,7 @@ function findMonorepoRoot(currentPath) {
const packageJsonPath = (0, node_path_1.join)(currentPath, 'package.json'); const packageJsonPath = (0, node_path_1.join)(currentPath, 'package.json');
const pnpmWorkspacePath = (0, node_path_1.join)(currentPath, 'pnpm-workspace.yaml'); const pnpmWorkspacePath = (0, node_path_1.join)(currentPath, 'pnpm-workspace.yaml');
if ((0, node_fs_1.existsSync)(pnpmWorkspacePath) || if ((0, node_fs_1.existsSync)(pnpmWorkspacePath) ||
((0, node_fs_1.existsSync)(packageJsonPath) && ((0, node_fs_1.existsSync)(packageJsonPath) && JSON.parse((0, node_fs_1.readFileSync)(packageJsonPath, 'utf-8')).workspaces)) {
JSON.parse((0, node_fs_1.readFileSync)(packageJsonPath, 'utf-8')).workspaces)) {
return currentPath; return currentPath;
} }
const parentPath = (0, node_path_1.dirname)(currentPath); const parentPath = (0, node_path_1.dirname)(currentPath);

View file

@ -5,6 +5,7 @@ const tslib_1 = require("tslib");
const path_1 = require("path"); const path_1 = require("path");
const colors_1 = tslib_1.__importDefault(require("../colors")); const colors_1 = tslib_1.__importDefault(require("../colors"));
const errors_1 = require("../errors"); const errors_1 = require("../errors");
const log_1 = require("../log");
const node_1 = require("./node"); const node_1 = require("./node");
const subprocess_1 = require("./subprocess"); const subprocess_1 = require("./subprocess");
async function runNativeRun(args, options = {}) { async function runNativeRun(args, options = {}) {
@ -39,6 +40,10 @@ async function getPlatformTargets(platformName) {
const err = JSON.parse(e); const err = JSON.parse(e);
errors.push(err); errors.push(err);
} }
if (errors.length === 0) {
log_1.logger.info('No devices found.');
return [];
}
const plural = errors.length > 1 ? 's' : ''; const plural = errors.length > 1 ? 's' : '';
const errMsg = `${colors_1.default.strong('native-run')} failed with error${plural}\n const errMsg = `${colors_1.default.strong('native-run')} failed with error${plural}\n
${errors ${errors

View file

@ -1,8 +1,8 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveNode = exports.requireTS = void 0; exports.resolveNode = exports.requireTS = void 0;
const utils_fs_1 = require("@ionic/utils-fs");
const fs_1 = require("fs"); const fs_1 = require("fs");
const fs_extra_1 = require("fs-extra");
const path_1 = require("path"); const path_1 = require("path");
/** /**
* @see https://github.com/ionic-team/stencil/blob/HEAD/src/compiler/sys/node-require.ts * @see https://github.com/ionic-team/stencil/blob/HEAD/src/compiler/sys/node-require.ts
@ -12,7 +12,7 @@ const requireTS = (ts, p) => {
delete require.cache[id]; delete require.cache[id];
require.extensions['.ts'] = (module, fileName) => { require.extensions['.ts'] = (module, fileName) => {
var _a; var _a;
let sourceText = (0, utils_fs_1.readFileSync)(fileName, 'utf8'); let sourceText = (0, fs_extra_1.readFileSync)(fileName, 'utf8');
if (fileName.endsWith('.ts')) { if (fileName.endsWith('.ts')) {
const tsResults = ts.transpileModule(sourceText, { const tsResults = ts.transpileModule(sourceText, {
fileName, fileName,

View file

@ -2,7 +2,7 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.lazy = exports.LazyPromise = exports.allSerial = void 0; exports.lazy = exports.LazyPromise = exports.allSerial = void 0;
function allSerial(funcs) { function allSerial(funcs) {
return funcs.reduce((promise, func) => promise.then(result => func().then(x => result.concat(x))), Promise.resolve([])); return funcs.reduce((promise, func) => promise.then((result) => func().then((x) => result.concat(x))), Promise.resolve([]));
} }
exports.allSerial = allSerial; exports.allSerial = allSerial;
class LazyPromise extends Promise { class LazyPromise extends Promise {

View file

@ -1,12 +1,20 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.generatePackageFile = exports.findPackageSwiftFile = exports.checkPackageManager = void 0; exports.addInfoPlistDebugIfNeeded = exports.runCocoapodsDeintegrate = exports.generatePackageText = exports.removeCocoapodsFiles = exports.extractSPMPackageDirectory = exports.checkPluginsForPackageSwift = exports.generatePackageFile = exports.findPackageSwiftFile = exports.checkPackageManager = void 0;
const utils_fs_1 = require("@ionic/utils-fs"); const fs_extra_1 = require("fs-extra");
const os_1 = require("os");
const path_1 = require("path"); const path_1 = require("path");
const plist_1 = require("plist");
const tar_1 = require("tar");
const common_1 = require("../common");
const errors_1 = require("../errors");
const common_2 = require("../ios/common");
const log_1 = require("../log"); const log_1 = require("../log");
const plugin_1 = require("../plugin");
const subprocess_1 = require("../util/subprocess");
async function checkPackageManager(config) { async function checkPackageManager(config) {
const iosDirectory = config.ios.nativeProjectDirAbs; const iosDirectory = config.ios.nativeProjectDirAbs;
if ((0, utils_fs_1.existsSync)((0, path_1.resolve)(iosDirectory, 'CapApp-SPM'))) { if ((0, fs_extra_1.existsSync)((0, path_1.resolve)(iosDirectory, 'CapApp-SPM'))) {
return 'SPM'; return 'SPM';
} }
return 'Cocoapods'; return 'Cocoapods';
@ -20,20 +28,60 @@ exports.findPackageSwiftFile = findPackageSwiftFile;
async function generatePackageFile(config, plugins) { async function generatePackageFile(config, plugins) {
const packageSwiftFile = await findPackageSwiftFile(config); const packageSwiftFile = await findPackageSwiftFile(config);
try { try {
log_1.logger.warn('SPM Support is still experimental'); log_1.logger.info('Writing Package.swift');
const textToWrite = generatePackageText(config, plugins); const textToWrite = await generatePackageText(config, plugins);
(0, utils_fs_1.writeFileSync)(packageSwiftFile, textToWrite); (0, fs_extra_1.writeFileSync)(packageSwiftFile, textToWrite);
} }
catch (err) { catch (err) {
log_1.logger.error(`Unable to write to ${packageSwiftFile}. Verify it is not already open. \n Error: ${err}`); log_1.logger.error(`Unable to write to ${packageSwiftFile}. Verify it is not already open. \n Error: ${err}`);
} }
} }
exports.generatePackageFile = generatePackageFile; exports.generatePackageFile = generatePackageFile;
function generatePackageText(config, plugins) { async function checkPluginsForPackageSwift(config, plugins) {
const iOSCapacitorPlugins = plugins.filter((p) => (0, plugin_1.getPluginType)(p, 'ios') === 0 /* PluginType.Core */);
const packageSwiftPluginList = await pluginsWithPackageSwift(iOSCapacitorPlugins);
if (plugins.length == packageSwiftPluginList.length) {
log_1.logger.debug(`Found ${plugins.length} iOS plugins, ${packageSwiftPluginList.length} have a Package.swift file`);
log_1.logger.info('All plugins have a Package.swift file and will be included in Package.swift');
}
else {
log_1.logger.warn('Some installed packages my not be compatable with SPM');
}
return packageSwiftPluginList;
}
exports.checkPluginsForPackageSwift = checkPluginsForPackageSwift;
async function extractSPMPackageDirectory(config) {
const spmDirectory = (0, path_1.join)(config.ios.nativeProjectDirAbs, 'CapApp-SPM');
const spmTemplate = (0, path_1.join)(config.cli.assetsDirAbs, 'ios-spm-template.tar.gz');
const debugConfig = (0, path_1.join)(config.ios.platformDirAbs, 'debug.xcconfig');
log_1.logger.info('Extracting ' + spmTemplate + ' to ' + spmDirectory);
try {
const tempCapDir = await (0, fs_extra_1.mkdtemp)((0, path_1.join)((0, os_1.tmpdir)(), 'cap-'));
const tempCapSPM = (0, path_1.join)(tempCapDir, 'App', 'CapApp-SPM');
const tempDebugXCConfig = (0, path_1.join)(tempCapDir, 'debug.xcconfig');
await (0, tar_1.extract)({ file: spmTemplate, cwd: tempCapDir });
await (0, fs_extra_1.move)(tempCapSPM, spmDirectory);
await (0, fs_extra_1.move)(tempDebugXCConfig, debugConfig);
}
catch (err) {
(0, errors_1.fatal)('Failed to create ' + spmDirectory + ' with error: ' + err);
}
}
exports.extractSPMPackageDirectory = extractSPMPackageDirectory;
async function removeCocoapodsFiles(config) {
const iosDirectory = config.ios.nativeProjectDirAbs;
const podFile = (0, path_1.resolve)(iosDirectory, 'Podfile');
const podlockFile = (0, path_1.resolve)(iosDirectory, 'Podfile.lock');
const xcworkspaceFile = (0, path_1.resolve)(iosDirectory, 'App.xcworkspace');
await (0, fs_extra_1.remove)(podFile);
await (0, fs_extra_1.remove)(podlockFile);
await (0, fs_extra_1.remove)(xcworkspaceFile);
}
exports.removeCocoapodsFiles = removeCocoapodsFiles;
async function generatePackageText(config, plugins) {
var _a, _b, _c; var _a, _b, _c;
const pbx = (0, utils_fs_1.readFileSync)((0, path_1.join)(config.ios.nativeXcodeProjDirAbs, 'project.pbxproj'), 'utf-8'); const iosPlatformVersion = await (0, common_1.getCapacitorPackageVersion)(config, config.ios.name);
const searchString = 'IPHONEOS_DEPLOYMENT_TARGET = '; const iosVersion = (0, common_2.getMajoriOSVersion)(config);
const iosVersion = pbx.substring(pbx.indexOf(searchString) + searchString.length, pbx.indexOf(searchString) + searchString.length + 2);
let packageSwiftText = `// swift-tools-version: 5.9 let packageSwiftText = `// swift-tools-version: 5.9
import PackageDescription import PackageDescription
@ -47,10 +95,15 @@ let package = Package(
targets: ["CapApp-SPM"]) targets: ["CapApp-SPM"])
], ],
dependencies: [ dependencies: [
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", branch: "main")`; .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", exact: "${iosPlatformVersion}")`;
for (const plugin of plugins) { for (const plugin of plugins) {
const relPath = (0, path_1.relative)(config.ios.nativeXcodeProjDirAbs, plugin.rootPath); if ((0, plugin_1.getPluginType)(plugin, config.ios.name) === 1 /* PluginType.Cordova */) {
packageSwiftText += `,\n .package(name: "${(_a = plugin.ios) === null || _a === void 0 ? void 0 : _a.name}", path: "${relPath}")`; packageSwiftText += `,\n .package(name: "${plugin.name}", path: "../../capacitor-cordova-ios-plugins/sources/${plugin.name}")`;
}
else {
const relPath = (0, path_1.relative)(config.ios.nativeXcodeProjDirAbs, plugin.rootPath);
packageSwiftText += `,\n .package(name: "${(_a = plugin.ios) === null || _a === void 0 ? void 0 : _a.name}", path: "${relPath}")`;
}
} }
packageSwiftText += ` packageSwiftText += `
], ],
@ -71,3 +124,64 @@ let package = Package(
`; `;
return packageSwiftText; return packageSwiftText;
} }
exports.generatePackageText = generatePackageText;
async function runCocoapodsDeintegrate(config) {
const podPath = await config.ios.podPath;
const projectFileName = config.ios.nativeXcodeProjDirAbs;
const useBundler = podPath.startsWith('bundle') && (await (0, subprocess_1.isInstalled)('bundle'));
const podCommandExists = await (0, subprocess_1.isInstalled)('pod');
if (useBundler)
log_1.logger.info('Found bundler, using it to run CocoaPods.');
log_1.logger.info('Running pod deintegrate on project ' + projectFileName);
if (useBundler || podCommandExists) {
if (useBundler) {
await (0, subprocess_1.runCommand)('bundle', ['exec', 'pod', 'deintegrate', projectFileName], {
cwd: config.ios.nativeProjectDirAbs,
});
}
else {
await (0, subprocess_1.runCommand)(podPath, ['deintegrate', projectFileName], {
cwd: config.ios.nativeProjectDirAbs,
});
}
}
else {
log_1.logger.warn('Skipping pod deintegrate because CocoaPods is not installed - migration will be incomplete');
}
}
exports.runCocoapodsDeintegrate = runCocoapodsDeintegrate;
async function addInfoPlistDebugIfNeeded(config) {
const infoPlist = (0, path_1.resolve)(config.ios.nativeTargetDirAbs, 'Info.plist');
log_1.logger.info('Checking ' + infoPlist + ' for CAPACITOR_DEBUG');
if ((0, fs_extra_1.existsSync)(infoPlist)) {
const infoPlistContents = (0, fs_extra_1.readFileSync)(infoPlist, 'utf-8');
const plistEntries = (0, plist_1.parse)(infoPlistContents);
if (plistEntries['CAPACITOR_DEBUG'] === undefined) {
log_1.logger.info('Writing CAPACITOR_DEBUG to ' + infoPlist);
plistEntries['CAPACITOR_DEBUG'] = '$(CAPACITOR_DEBUG)';
const plistToWrite = (0, plist_1.build)(plistEntries);
(0, fs_extra_1.writeFileSync)(infoPlist, plistToWrite);
}
else {
log_1.logger.warn('Found CAPACITOR_DEBUG set to ' + plistEntries['CAPACITOR_DEBUG'] + ', skipping.');
}
}
else {
log_1.logger.warn(infoPlist + ' not found.');
}
}
exports.addInfoPlistDebugIfNeeded = addInfoPlistDebugIfNeeded;
// Private Functions
async function pluginsWithPackageSwift(plugins) {
const pluginList = [];
for (const plugin of plugins) {
const packageSwiftFound = await (0, fs_extra_1.pathExists)((0, path_1.join)(plugin.rootPath, 'Package.swift'));
if (packageSwiftFound) {
pluginList.push(plugin);
}
else {
log_1.logger.warn(plugin.id + ' does not have a Package.swift');
}
}
return pluginList;
}

View file

@ -10,13 +10,7 @@ async function runCommand(command, args, options = {}) {
catch (e) { catch (e) {
if (e instanceof utils_subprocess_1.SubprocessError) { if (e instanceof utils_subprocess_1.SubprocessError) {
// old behavior of just throwing the stdout/stderr strings // old behavior of just throwing the stdout/stderr strings
throw e.output throw e.output ? e.output : e.cause ? `${e.message} ${e.cause.toString()}` : e.code ? e.code : 'Unknown error';
? e.output
: e.code
? e.code
: e.error
? e.error.message
: 'Unknown error';
} }
throw e; throw e;
} }

View file

@ -2,10 +2,10 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.extractTemplate = void 0; exports.extractTemplate = void 0;
const tslib_1 = require("tslib"); const tslib_1 = require("tslib");
const utils_fs_1 = require("@ionic/utils-fs"); const fs_extra_1 = require("fs-extra");
const tar_1 = tslib_1.__importDefault(require("tar")); const tar_1 = tslib_1.__importDefault(require("tar"));
async function extractTemplate(src, dir) { async function extractTemplate(src, dir) {
await (0, utils_fs_1.mkdirp)(dir); await (0, fs_extra_1.mkdirp)(dir);
await tar_1.default.extract({ file: src, cwd: dir }); await tar_1.default.extract({ file: src, cwd: dir });
} }
exports.extractTemplate = extractTemplate; exports.extractTemplate = extractTemplate;

View file

@ -18,7 +18,7 @@ const checkInteractive = (...args) => {
} }
// Make sure none of the provided args are empty, otherwise print the interactive // Make sure none of the provided args are empty, otherwise print the interactive
// warning and return false // warning and return false
if (args.filter(arg => !arg).length) { if (args.filter((arg) => !arg).length) {
log_1.logger.error(`Non-interactive shell detected.\n` + log_1.logger.error(`Non-interactive shell detected.\n` +
`Run the command with ${colors_1.default.input('--help')} to see a list of arguments that must be provided.`); `Run the command with ${colors_1.default.input('--help')} to see a list of arguments that must be provided.`);
return false; return false;

View file

@ -2,7 +2,7 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.uuidv4 = void 0; exports.uuidv4 = void 0;
function uuidv4() { function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = (Math.random() * 16) | 0; const r = (Math.random() * 16) | 0;
const v = c == 'x' ? r : (r & 0x3) | 0x8; const v = c == 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16); return v.toString(16);

View file

@ -2,12 +2,12 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.buildXmlElement = exports.writeXML = exports.parseXML = exports.readXML = void 0; exports.buildXmlElement = exports.writeXML = exports.parseXML = exports.readXML = void 0;
const tslib_1 = require("tslib"); const tslib_1 = require("tslib");
const utils_fs_1 = require("@ionic/utils-fs"); const fs_extra_1 = require("fs-extra");
const xml2js_1 = tslib_1.__importDefault(require("xml2js")); const xml2js_1 = tslib_1.__importDefault(require("xml2js"));
async function readXML(path) { async function readXML(path) {
var _a; var _a;
try { try {
const xmlStr = await (0, utils_fs_1.readFile)(path, { encoding: 'utf-8' }); const xmlStr = await (0, fs_extra_1.readFile)(path, { encoding: 'utf-8' });
try { try {
return await xml2js_1.default.parseStringPromise(xmlStr); return await xml2js_1.default.parseStringPromise(xmlStr);
} }
@ -21,9 +21,7 @@ async function readXML(path) {
} }
exports.readXML = readXML; exports.readXML = readXML;
function parseXML(xmlStr, options) { function parseXML(xmlStr, options) {
const parser = options !== undefined const parser = options !== undefined ? new xml2js_1.default.Parser({ ...options }) : new xml2js_1.default.Parser();
? new xml2js_1.default.Parser({ ...options })
: new xml2js_1.default.Parser();
let xmlObj; let xmlObj;
parser.parseString(xmlStr, (err, result) => { parser.parseString(xmlStr, (err, result) => {
if (!err) { if (!err) {
@ -34,7 +32,7 @@ function parseXML(xmlStr, options) {
} }
exports.parseXML = parseXML; exports.parseXML = parseXML;
async function writeXML(object) { async function writeXML(object) {
return new Promise(resolve => { return new Promise((resolve) => {
const builder = new xml2js_1.default.Builder({ const builder = new xml2js_1.default.Builder({
headless: true, headless: true,
explicitRoot: false, explicitRoot: false,

View file

@ -1,22 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.copyWeb = void 0;
const tslib_1 = require("tslib");
const utils_fs_1 = require("@ionic/utils-fs");
const path_1 = require("path");
const colors_1 = tslib_1.__importDefault(require("../colors"));
const common_1 = require("../common");
const errors_1 = require("../errors");
const node_1 = require("../util/node");
async function copyWeb(config) {
if (config.app.bundledWebRuntime) {
const runtimePath = (0, node_1.resolveNode)(config.app.rootDir, '@capacitor/core', 'dist', 'capacitor.js');
if (!runtimePath) {
(0, errors_1.fatal)(`Unable to find ${colors_1.default.strong('node_modules/@capacitor/core/dist/capacitor.js')}.\n` + `Are you sure ${colors_1.default.strong('@capacitor/core')} is installed?`);
}
return (0, common_1.runTask)(`Copying ${colors_1.default.strong('capacitor.js')} to web dir`, () => {
return (0, utils_fs_1.copy)(runtimePath, (0, path_1.join)(config.app.webDirAbs, 'capacitor.js'));
});
}
}
exports.copyWeb = copyWeb;

1
@capacitor/cli/node_modules/.bin/glob generated vendored Symbolic link
View file

@ -0,0 +1 @@
../glob/dist/esm/bin.mjs

View file

@ -1 +1 @@
../rimraf/dist/cjs/src/bin.js ../rimraf/dist/esm/bin.mjs

View file

@ -0,0 +1,185 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.1.6](https://github.com/ionic-team/ionic-cli/compare/@ionic/utils-array@2.1.5...@ionic/utils-array@2.1.6) (2023-03-29)
**Note:** Version bump only for package @ionic/utils-array
## [2.1.5](https://github.com/ionic-team/ionic-cli/compare/@ionic/utils-array@2.1.4...@ionic/utils-array@2.1.5) (2020-08-28)
**Note:** Version bump only for package @ionic/utils-array
## [2.1.4](https://github.com/ionic-team/ionic-cli/compare/@ionic/utils-array@2.1.3...@ionic/utils-array@2.1.4) (2020-08-25)
**Note:** Version bump only for package @ionic/utils-array
## [2.1.3](https://github.com/ionic-team/ionic-cli/compare/@ionic/utils-array@2.1.2...@ionic/utils-array@2.1.3) (2020-05-12)
### Bug Fixes
* pin tslib to avoid "Cannot set property pathExists" error ([689e1f0](https://github.com/ionic-team/ionic-cli/commit/689e1f038b907356ef855a067a76d4822e7072a8))
## [2.1.2](https://github.com/ionic-team/ionic-cli/compare/@ionic/utils-array@2.1.1...@ionic/utils-array@2.1.2) (2020-05-06)
**Note:** Version bump only for package @ionic/utils-array
## [2.1.1](https://github.com/ionic-team/ionic-cli/compare/@ionic/utils-array@2.1.0...@ionic/utils-array@2.1.1) (2020-03-03)
**Note:** Version bump only for package @ionic/utils-array
# 2.1.0 (2020-02-11)
### Features
* **start:** add new list starter option ([#4315](https://github.com/ionic-team/ionic-cli/issues/4315)) ([1df44c1](https://github.com/ionic-team/ionic-cli/commit/1df44c1591f37b89f2b672857740edd6cb2aea67))
## [2.0.2](https://github.com/ionic-team/ionic-cli/compare/@ionic/utils-array@2.0.1...@ionic/utils-array@2.0.2) (2020-02-10)
**Note:** Version bump only for package @ionic/utils-array
## [2.0.1](https://github.com/ionic-team/ionic-cli/compare/@ionic/utils-array@2.0.0...@ionic/utils-array@2.0.1) (2020-02-03)
**Note:** Version bump only for package @ionic/utils-array
# [2.0.0](https://github.com/ionic-team/ionic-cli/compare/@ionic/utils-array@1.2.2...@ionic/utils-array@2.0.0) (2020-01-25)
### chore
* require Node 10 ([5a47874](https://github.com/ionic-team/ionic-cli/commit/5a478746c074207b6dc96aa8771f04a606deb1ef))
### BREAKING CHANGES
* A minimum of Node.js 10.3.0 is required.
## [1.2.2](https://github.com/ionic-team/ionic-cli/compare/@ionic/utils-array@1.2.1...@ionic/utils-array@1.2.2) (2019-12-05)
**Note:** Version bump only for package @ionic/utils-array
## [1.2.1](https://github.com/ionic-team/ionic-cli/compare/@ionic/utils-array@1.2.0...@ionic/utils-array@1.2.1) (2019-09-18)
**Note:** Version bump only for package @ionic/utils-array
# [1.2.0](https://github.com/ionic-team/ionic-cli/compare/@ionic/utils-array@1.1.1...@ionic/utils-array@1.2.0) (2019-08-28)
### Features
* **replace:** add replace item in array by index function ([011ddf7](https://github.com/ionic-team/ionic-cli/commit/011ddf7))
* **splice:** add non-mutating splice function ([758d287](https://github.com/ionic-team/ionic-cli/commit/758d287))
## [1.1.1](https://github.com/ionic-team/ionic-cli/compare/@ionic/utils-array@1.1.0...@ionic/utils-array@1.1.1) (2019-08-23)
**Note:** Version bump only for package @ionic/utils-array
# [1.1.0](https://github.com/ionic-team/ionic-cli/compare/@ionic/utils-array@1.0.2...@ionic/utils-array@1.1.0) (2019-08-14)
### Features
* add new `move` function ([ba8da3b](https://github.com/ionic-team/ionic-cli/commit/ba8da3b))
## [1.0.2](https://github.com/ionic-team/ionic-cli/compare/@ionic/utils-array@1.0.1...@ionic/utils-array@1.0.2) (2019-08-07)
**Note:** Version bump only for package @ionic/utils-array
## [1.0.1](https://github.com/ionic-team/ionic-cli/compare/@ionic/utils-array@1.0.0...@ionic/utils-array@1.0.1) (2019-06-05)
**Note:** Version bump only for package @ionic/utils-array
# [1.0.0](https://github.com/ionic-team/ionic-cli/compare/@ionic/utils-array@0.0.1...@ionic/utils-array@1.0.0) (2019-05-29)
### chore
* require Node 8 ([5670e68](https://github.com/ionic-team/ionic-cli/commit/5670e68))
### BREAKING CHANGES
* A minimum of Node.js 8.9.4 is required.
<a name="0.0.1"></a>
## 0.0.1 (2019-02-27)
**Note:** Version bump only for package @ionic/utils-array

21
@capacitor/cli/node_modules/@ionic/utils-array/LICENSE generated vendored Normal file
View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2017 Drifty Co
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1 @@
# @ionic/utils-array

View file

@ -0,0 +1,39 @@
export declare function conform<T>(t?: T | T[]): T[];
export declare function concurrentFilter<T>(array: T[], callback: (currentValue: T) => Promise<boolean>): Promise<T[]>;
export declare function filter<T>(array: T[], callback: (currentValue: T, currentIndex: number, array: readonly T[]) => Promise<boolean>): Promise<T[]>;
export declare function filter<T>(array: readonly T[], callback: (currentValue: T, currentIndex: number, array: readonly T[]) => Promise<boolean>): Promise<readonly T[]>;
export declare function map<T, U>(array: T[], callback: (currentValue: T, currentIndex: number, array: readonly T[]) => Promise<U>): Promise<U[]>;
export declare function map<T, U>(array: T[], callback: (currentValue: T, currentIndex: number, array: readonly T[]) => Promise<U>): Promise<readonly U[]>;
export declare function map<T, U>(array: readonly T[], callback: (currentValue: T, currentIndex: number, array: readonly T[]) => Promise<U>): Promise<U[]>;
export declare function map<T, U>(array: readonly T[], callback: (currentValue: T, currentIndex: number, array: readonly T[]) => Promise<U>): Promise<readonly U[]>;
export declare function reduce<T>(array: T[], callback: (accumulator: T, currentValue: T, currentIndex: number, array: readonly T[]) => Promise<T>): Promise<T>;
export declare function reduce<T>(array: T[], callback: (accumulator: T, currentValue: T, currentIndex: number, array: readonly T[]) => Promise<T>, initialValue: T): Promise<T>;
export declare function reduce<T, R>(array: T[], callback: (accumulator: R, currentValue: T, currentIndex: number, array: readonly T[]) => Promise<R>): Promise<R>;
export declare function reduce<T, U>(array: T[], callback: (accumulator: U, currentValue: T, currentIndex: number, array: readonly T[]) => Promise<U>, initialValue: U): Promise<U>;
export declare function reduce<T>(array: readonly T[], callback: (accumulator: T, currentValue: T, currentIndex: number, array: readonly T[]) => Promise<T>): Promise<T>;
export declare function reduce<T>(array: readonly T[], callback: (accumulator: T, currentValue: T, currentIndex: number, array: readonly T[]) => Promise<T>, initialValue: T): Promise<T>;
export declare function reduce<T, R>(array: readonly T[], callback: (accumulator: R, currentValue: T, currentIndex: number, array: readonly T[]) => Promise<R>): Promise<R>;
export declare function reduce<T, U>(array: readonly T[], callback: (accumulator: U, currentValue: T, currentIndex: number, array: readonly T[]) => Promise<U>, initialValue: U): Promise<U>;
/**
* Splice an array.
*
* This function will return a new array with the standard splice behavior
* applied. Unlike the standard array splice, the array of removed items is not
* returned.
*/
export declare function splice<T>(array: readonly T[], start: number, deleteCount?: number, ...items: T[]): T[];
/**
* Move an item in an array by index.
*
* This function will return a new array with the item in the `fromIndex`
* position moved to the `toIndex` position. If `fromIndex` or `toIndex` are
* out of bounds, the array items remain unmoved.
*/
export declare function move<T>(array: readonly T[], fromIndex: number, toIndex: number): T[];
/**
* Replace an item in an array by index.
*
* This function will return a new array with the item in the `index` position
* replaced with `item`. If `index` is out of bounds, the item is not replaced.
*/
export declare function replace<T>(array: readonly T[], index: number, item: T): T[];

View file

@ -0,0 +1,97 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.replace = exports.move = exports.splice = exports.reduce = exports.map = exports.filter = exports.concurrentFilter = exports.conform = void 0;
function conform(t) {
if (typeof t === 'undefined') {
return [];
}
if (!Array.isArray(t)) {
return [t];
}
return t;
}
exports.conform = conform;
async function concurrentFilter(array, callback) {
const mapper = async (v) => [v, await callback(v)];
const mapped = await Promise.all(array.map(mapper));
return mapped
.filter(([, f]) => f)
.map(([v]) => v);
}
exports.concurrentFilter = concurrentFilter;
async function filter(array, callback) {
const initial = [];
return reduce(array, async (acc, v, i, arr) => {
if (await callback(v, i, arr)) {
acc.push(v);
}
return acc;
}, initial);
}
exports.filter = filter;
async function map(array, callback) {
const initial = [];
return reduce(array, async (acc, v, i, arr) => {
acc.push(await callback(v, i, arr));
return acc;
}, initial);
}
exports.map = map;
async function reduce(array, callback, initialValue) {
const hadInitialValue = typeof initialValue === 'undefined';
const startingIndex = hadInitialValue ? 1 : 0;
if (typeof initialValue === 'undefined') {
if (array.length === 0) {
throw new TypeError('Reduce of empty array with no initial value');
}
initialValue = array[0];
}
let value = initialValue;
for (let i = startingIndex; i < array.length; i++) {
const v = await callback(value, array[i], i, array);
value = v;
}
return value;
}
exports.reduce = reduce;
/**
* Splice an array.
*
* This function will return a new array with the standard splice behavior
* applied. Unlike the standard array splice, the array of removed items is not
* returned.
*/
function splice(array, start, deleteCount = array.length - start, ...items) {
const result = [...array];
result.splice(start, deleteCount, ...items);
return result;
}
exports.splice = splice;
/**
* Move an item in an array by index.
*
* This function will return a new array with the item in the `fromIndex`
* position moved to the `toIndex` position. If `fromIndex` or `toIndex` are
* out of bounds, the array items remain unmoved.
*/
function move(array, fromIndex, toIndex) {
const element = array[fromIndex];
if (fromIndex < 0 || toIndex < 0 || fromIndex >= array.length || toIndex >= array.length) {
return [...array];
}
return splice(splice(array, fromIndex, 1), toIndex, 0, element);
}
exports.move = move;
/**
* Replace an item in an array by index.
*
* This function will return a new array with the item in the `index` position
* replaced with `item`. If `index` is out of bounds, the item is not replaced.
*/
function replace(array, index, item) {
if (index < 0 || index > array.length) {
return [...array];
}
return splice(array, index, 1, item);
}
exports.replace = replace;

View file

@ -0,0 +1,49 @@
{
"name": "@ionic/utils-array",
"version": "2.1.6",
"description": "Array utils",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"homepage": "https://ionicframework.com/",
"author": "Ionic Team <hi@ionic.io> (https://ionic.io)",
"license": "MIT",
"engines": {
"node": ">=16.0.0"
},
"files": [
"dist/",
"LICENSE",
"README.md"
],
"repository": {
"type": "git",
"url": "https://github.com/ionic-team/ionic-cli.git"
},
"bugs": {
"url": "https://github.com/ionic-team/ionic-cli/issues"
},
"scripts": {
"clean": "rimraf dist",
"lint": "true",
"build": "npm run clean && tsc",
"watch": "tsc -w --preserveWatchOutput",
"test": "jest --maxWorkers=4",
"prepublishOnly": "npm run build"
},
"dependencies": {
"debug": "^4.0.0",
"tslib": "^2.0.1"
},
"devDependencies": {
"@types/debug": "^4.1.1",
"@types/jest": "^26.0.10",
"@types/node": "~16.0.0",
"jest": "^26.4.2",
"jest-cli": "^26.0.1",
"lint-staged": "^10.0.2",
"rimraf": "^3.0.0",
"ts-jest": "~26.3.0",
"typescript": "~4.8.0"
},
"gitHead": "15ef6e7da4eace4fd55d16fd9508d156a4bc8203"
}

View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2017 Drifty Co
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1 @@
# @ionic/utils-stream

View file

@ -0,0 +1,39 @@
/// <reference types="node" />
/// <reference types="node" />
import { Readable, ReadableOptions, Writable, WritableOptions } from 'stream';
export declare class NullStream extends Writable {
_write(chunk: any, encoding: string, callback: () => void): void;
}
export interface ReadableStreamBufferOptions extends ReadableOptions {
chunkSize?: number;
allocSize?: number;
growSize?: number;
}
export declare class ReadableStreamBuffer extends Readable {
protected buffer: Buffer;
protected _size: number;
protected _stopped: boolean;
protected chunkSize: number;
protected growSize: number;
constructor(opts?: ReadableStreamBufferOptions);
get size(): number;
get stopped(): boolean;
_read(): void;
feed(data: Buffer | string, encoding?: BufferEncoding): void;
stop(): void;
protected _send(): void;
}
export interface WritableStreamBufferOptions extends WritableOptions {
allocSize?: number;
growSize?: number;
}
export declare class WritableStreamBuffer extends Writable {
protected buffer: Buffer;
protected _size: number;
protected growSize: number;
constructor(opts?: WritableStreamBufferOptions);
get size(): number;
_write(chunk: any, encoding: string, callback: () => void): void;
consume(bytes?: number): Buffer;
}
export declare function growBufferForAppendedData(buf: Buffer, actualsize: number, appendsize: number): Buffer;

View file

@ -0,0 +1,108 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.growBufferForAppendedData = exports.WritableStreamBuffer = exports.ReadableStreamBuffer = exports.NullStream = void 0;
const stream_1 = require("stream");
const DEFAULT_CHUNK_SIZE = 4;
const DEFAULT_ALLOC_SIZE = 32;
const DEFAULT_GROW_SIZE = 16;
class NullStream extends stream_1.Writable {
_write(chunk, encoding, callback) {
callback();
}
}
exports.NullStream = NullStream;
class ReadableStreamBuffer extends stream_1.Readable {
constructor(opts) {
super(opts);
this._size = 0;
this._stopped = false;
this.buffer = Buffer.alloc(opts && opts.allocSize ? opts.allocSize : DEFAULT_ALLOC_SIZE);
this.chunkSize = opts && opts.chunkSize ? opts.chunkSize : DEFAULT_CHUNK_SIZE;
this.growSize = opts && opts.growSize ? opts.growSize : DEFAULT_GROW_SIZE;
}
get size() {
return this._size;
}
get stopped() {
return this._stopped;
}
_read() {
this._send();
}
feed(data, encoding = 'utf8') {
if (this._stopped) {
throw new Error('ReadableStreamBuffer is stopped. Can no longer feed.');
}
const datasize = typeof data === 'string' ? Buffer.byteLength(data) : data.length;
this.buffer = growBufferForAppendedData(this.buffer, this._size, Math.ceil(datasize / this.growSize) * this.growSize);
if (typeof data === 'string') {
this.buffer.write(data, this._size, datasize, encoding);
}
else {
this.buffer.copy(data, this._size, 0);
}
this._size += datasize;
}
stop() {
if (this._stopped) {
return;
}
this._stopped = true;
if (this._size === 0) {
this.push(null);
}
}
_send() {
const chunkSize = Math.min(this.chunkSize, this._size);
let done = false;
if (chunkSize > 0) {
const chunk = Buffer.alloc(chunkSize);
this.buffer.copy(chunk, 0, 0, chunkSize);
done = !this.push(chunk);
this.buffer.copy(this.buffer, 0, chunkSize, this._size);
this._size -= chunkSize;
}
if (this._size === 0 && this._stopped) {
this.push(null);
}
if (!done) {
setTimeout(() => this._send(), 1);
}
}
}
exports.ReadableStreamBuffer = ReadableStreamBuffer;
class WritableStreamBuffer extends stream_1.Writable {
constructor(opts) {
super(opts);
this._size = 0;
this.buffer = Buffer.alloc(opts && opts.allocSize ? opts.allocSize : DEFAULT_ALLOC_SIZE);
this.growSize = opts && opts.growSize ? opts.growSize : DEFAULT_GROW_SIZE;
}
get size() {
return this._size;
}
_write(chunk, encoding, callback) {
this.buffer = growBufferForAppendedData(this.buffer, this._size, Math.ceil(chunk.length / this.growSize) * this.growSize);
chunk.copy(this.buffer, this._size, 0);
this._size += chunk.length;
callback();
}
consume(bytes) {
bytes = typeof bytes === 'number' ? bytes : this._size;
const data = Buffer.alloc(bytes);
this.buffer.copy(data, 0, 0, data.length);
this.buffer.copy(this.buffer, 0, data.length);
this._size -= data.length;
return data;
}
}
exports.WritableStreamBuffer = WritableStreamBuffer;
function growBufferForAppendedData(buf, actualsize, appendsize) {
if ((buf.length - actualsize) >= appendsize) {
return buf;
}
const newbuffer = Buffer.alloc(buf.length + appendsize);
buf.copy(newbuffer, 0, 0, actualsize);
return newbuffer;
}
exports.growBufferForAppendedData = growBufferForAppendedData;

View file

@ -0,0 +1,49 @@
{
"name": "@ionic/utils-stream",
"version": "3.1.7",
"description": "Stream utils for NodeJS",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"homepage": "https://ionicframework.com/",
"author": "Ionic Team <hi@ionic.io> (https://ionic.io)",
"license": "MIT",
"engines": {
"node": ">=16.0.0"
},
"files": [
"dist/",
"LICENSE",
"README.md"
],
"repository": {
"type": "git",
"url": "https://github.com/ionic-team/ionic-cli.git"
},
"bugs": {
"url": "https://github.com/ionic-team/ionic-cli/issues"
},
"scripts": {
"clean": "rimraf dist",
"lint": "true",
"build": "npm run clean && tsc",
"watch": "tsc -w --preserveWatchOutput",
"test": "jest --maxWorkers=4",
"prepublishOnly": "npm run build"
},
"dependencies": {
"debug": "^4.0.0",
"tslib": "^2.0.1"
},
"devDependencies": {
"@types/debug": "^4.1.1",
"@types/jest": "^26.0.10",
"@types/node": "~16.0.0",
"jest": "^26.4.2",
"jest-cli": "^26.0.1",
"lint-staged": "^10.0.2",
"rimraf": "^3.0.0",
"stream-combiner2": "^1.1.1",
"ts-jest": "~26.3.0",
"typescript": "~4.8.0"
}
}

View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2017 Drifty Co
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Some files were not shown because too many files have changed in this diff Show more