Skip to content

Commit

Permalink
Merge branch 'main' into feature/http-gzip-support
Browse files Browse the repository at this point in the history
  • Loading branch information
Dante1349 authored Jun 29, 2023
2 parents 6620192 + 7906d36 commit 1a625fc
Show file tree
Hide file tree
Showing 12 changed files with 150 additions and 54 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ Made possible by the Capacitor community. 💖
<!-- CONTRIBUTORS:START -->

<p align="center">
<a href="https://github.com/yooouuri"><img src="https://github.com/yooouuri.png?size=100" width="50" height="50" /></a>
<a href="https://github.com/davidnussio"><img src="https://github.com/davidnussio.png?size=100" width="50" height="50" /></a>
<a href="https://github.com/ltm"><img src="https://github.com/ltm.png?size=100" width="50" height="50" /></a>
<a href="https://github.com/stewones"><img src="https://github.com/stewones.png?size=100" width="50" height="50" /></a>
Expand Down
72 changes: 33 additions & 39 deletions android/capacitor/src/main/java/com/getcapacitor/Bridge.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ public class Bridge {
private String appUrlConfig;
private HostMask appAllowNavigationMask;
private Set<String> allowedOriginRules = new HashSet<String>();
private ArrayList<String> authorities = new ArrayList<>();
// A reference to the main WebView for the app
private final WebView webView;
public final MockCordovaInterfaceImpl cordovaInterface;
Expand Down Expand Up @@ -208,7 +209,6 @@ private Bridge(
// Grab any intent info that our app was launched with
Intent intent = context.getIntent();
this.intentUri = intent.getData();

// Register our core plugins
this.registerAllPlugins();

Expand All @@ -231,51 +231,16 @@ private void setAllowedOriginRules() {
allowedOriginRules.add(allowNavigation);
}
}
authorities.addAll(Arrays.asList(appAllowNavigationConfig));
}
this.appAllowNavigationMask = HostMask.Parser.parse(appAllowNavigationConfig);
}

public App getApp() {
return app;
}

private void loadWebView() {
appUrlConfig = this.getServerUrl();
String[] appAllowNavigationConfig = this.config.getAllowNavigation();

ArrayList<String> authorities = new ArrayList<>();

if (appAllowNavigationConfig != null) {
authorities.addAll(Arrays.asList(appAllowNavigationConfig));
}
this.appAllowNavigationMask = HostMask.Parser.parse(appAllowNavigationConfig);
String authority = this.getHost();
authorities.add(authority);
String scheme = this.getScheme();

localUrl = scheme + "://" + authority;

if (appUrlConfig != null) {
try {
URL appUrlObject = new URL(appUrlConfig);
authorities.add(appUrlObject.getAuthority());
} catch (Exception ex) {
Logger.error("Provided server url is invalid: " + ex.getMessage());
return;
}
localUrl = appUrlConfig;
appUrl = appUrlConfig;
} else {
appUrl = localUrl;
// custom URL schemes requires path ending with /
if (!scheme.equals(Bridge.CAPACITOR_HTTP_SCHEME) && !scheme.equals(CAPACITOR_HTTPS_SCHEME)) {
appUrl += "/";
}
}

String appUrlPath = this.config.getStartPath();
if (appUrlPath != null && !appUrlPath.trim().isEmpty()) {
appUrl += appUrlPath;
}
final boolean html5mode = this.config.isHTML5Mode();

// Start the local web server
Expand All @@ -295,7 +260,6 @@ private void loadWebView() {
setServerBasePath(path);
}
}

if (!this.isMinimumWebViewInstalled()) {
String errorUrl = this.getErrorUrl();
if (errorUrl != null) {
Expand Down Expand Up @@ -586,6 +550,36 @@ private void initWebView() {
}

WebView.setWebContentsDebuggingEnabled(this.config.isWebContentsDebuggingEnabled());

appUrlConfig = this.getServerUrl();
String authority = this.getHost();
authorities.add(authority);
String scheme = this.getScheme();

localUrl = scheme + "://" + authority;

if (appUrlConfig != null) {
try {
URL appUrlObject = new URL(appUrlConfig);
authorities.add(appUrlObject.getAuthority());
} catch (Exception ex) {
Logger.error("Provided server url is invalid: " + ex.getMessage());
return;
}
localUrl = appUrlConfig;
appUrl = appUrlConfig;
} else {
appUrl = localUrl;
// custom URL schemes requires path ending with /
if (!scheme.equals(Bridge.CAPACITOR_HTTP_SCHEME) && !scheme.equals(CAPACITOR_HTTPS_SCHEME)) {
appUrl += "/";
}
}

String appUrlPath = this.config.getStartPath();
if (appUrlPath != null && !appUrlPath.trim().isEmpty()) {
appUrl += appUrlPath;
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
Expand Down Expand Up @@ -402,7 +403,7 @@ public static JSObject request(PluginCall call, String httpMethod, Bridge bridge

CapacitorHttpUrlConnection connection = connectionBuilder.build();

if (null != bridge) {
if (null != bridge && !isDomainExcludedFromSSL(bridge, url)) {
connection.setSSLSocketFactory(bridge);
}

Expand All @@ -420,6 +421,16 @@ public static JSObject request(PluginCall call, String httpMethod, Bridge bridge
return buildResponse(connection, responseType);
}

private static Boolean isDomainExcludedFromSSL(Bridge bridge, URL url) {
try {
Class<?> sslPinningImpl = Class.forName("io.ionic.sslpinning.SSLPinning");
Method method = sslPinningImpl.getDeclaredMethod("isDomainExcluded", Bridge.class, URL.class);
return (Boolean) method.invoke(sslPinningImpl.newInstance(), bridge, url);
} catch (Exception ignored) {
return false;
}
}

@FunctionalInterface
public interface ProgressEmitter {
void emit(Integer bytes, Integer contentLength);
Expand Down
78 changes: 67 additions & 11 deletions cli/src/android/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,6 @@ export async function buildAndroid(
: `assemble${flavor}Release`;
const gradleArgs = [arg];

if (
!buildOptions.keystorepath ||
!buildOptions.keystorealias ||
!buildOptions.keystorealiaspass ||
!buildOptions.keystorepass
) {
throw 'Missing options. Please supply all options for android signing. (Keystore Path, Keystore Password, Keystore Key Alias, Keystore Key Password)';
}

try {
await runTask('Running Gradle build', async () =>
runCommand('./gradlew', gradleArgs, {
Expand Down Expand Up @@ -63,6 +54,73 @@ export async function buildAndroid(
`-release-signed.${releaseType.toLowerCase()}`,
);

if (buildOptions.signingtype == 'jarsigner') {
await signWithJarSigner(
config,
buildOptions,
releasePath,
signedReleaseName,
unsignedReleaseName,
);
} else {
await signWithApkSigner(
config,
buildOptions,
releasePath,
signedReleaseName,
unsignedReleaseName,
);
}

logSuccess(`Successfully generated ${signedReleaseName} at: ${releasePath}`);
}

async function signWithApkSigner(
config: Config,
buildOptions: BuildCommandOptions,
releasePath: string,
signedReleaseName: string,
unsignedReleaseName: string,
) {
if (!buildOptions.keystorepath || !buildOptions.keystorepass) {
throw 'Missing options. Please supply all options for android signing. (Keystore Path, Keystore Password)';
}

const signingArgs = [
'sign',
'--ks',
buildOptions.keystorepath,
'--ks-pass',
`pass:${buildOptions.keystorepass}`,
'--in',
`${join(releasePath, unsignedReleaseName)}`,
'--out',
`${join(releasePath, signedReleaseName)}`,
];

await runTask('Signing Release', async () => {
await runCommand('apksigner', signingArgs, {
cwd: config.android.platformDirAbs,
});
});
}

async function signWithJarSigner(
config: Config,
buildOptions: BuildCommandOptions,
releasePath: string,
signedReleaseName: string,
unsignedReleaseName: string,
) {
if (
!buildOptions.keystorepath ||
!buildOptions.keystorealias ||
!buildOptions.keystorealiaspass ||
!buildOptions.keystorepass
) {
throw 'Missing options. Please supply all options for android signing. (Keystore Path, Keystore Password, Keystore Key Alias, Keystore Key Password)';
}

const signingArgs = [
'-sigalg',
'SHA1withRSA',
Expand All @@ -85,6 +143,4 @@ export async function buildAndroid(
cwd: config.android.platformDirAbs,
});
});

logSuccess(`Successfully generated ${signedReleaseName} at: ${releasePath}`);
}
3 changes: 0 additions & 3 deletions cli/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,9 +239,6 @@ async function loadAndroidConfig(
const buildOptions = {
keystorePath: extConfig.android?.buildOptions?.keystorePath,
keystorePassword: extConfig.android?.buildOptions?.keystorePassword,
keystoreAlias: extConfig.android?.buildOptions?.keystoreAlias,
keystoreAliasPassword:
extConfig.android?.buildOptions?.keystoreAliasPassword,
releaseType: extConfig.android?.buildOptions?.releaseType,
};

Expand Down
8 changes: 8 additions & 0 deletions cli/src/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,14 @@ export interface CapacitorConfig {
* @default "AAB"
*/
releaseType?: 'AAB' | 'APK';

/**
* Program to sign your build with
*
* @since 5.1.0
* @default "jarsigner"
*/
signingType?: 'apksigner' | 'jarsigner';
};

/**
Expand Down
1 change: 1 addition & 0 deletions cli/src/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export interface AndroidConfig extends PlatformConfig {
keystoreAlias?: string;
keystoreAliasPassword?: string;
releaseType?: 'AAB' | 'APK';
signingType?: 'apksigner' | 'jarsigner';
};
}

Expand Down
8 changes: 8 additions & 0 deletions cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ export function runProgram(config: Config): void {
'Android release type; APK or AAB',
).choices(['AAB', 'APK']),
)
.addOption(
new Option(
'--signing-type <signingtype>',
'Program used to sign apps (default: jarsigner)',
).choices(['apksigner', 'jarsigner']),
)
.action(
wrapAction(
telemetryAction(
Expand All @@ -168,6 +174,7 @@ export function runProgram(config: Config): void {
keystorealias,
keystorealiaspass,
androidreleasetype,
signingtype,
},
) => {
const { buildCommand } = await import('./tasks/build');
Expand All @@ -178,6 +185,7 @@ export function runProgram(config: Config): void {
keystorealias,
keystorealiaspass,
androidreleasetype,
signingtype,
});
},
),
Expand Down
5 changes: 5 additions & 0 deletions cli/src/tasks/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface BuildCommandOptions {
keystorealias?: string;
keystorealiaspass?: string;
androidreleasetype?: 'AAB' | 'APK';
signingtype?: 'apksigner' | 'jarsigner';
}

export async function buildCommand(
Expand Down Expand Up @@ -46,6 +47,10 @@ export async function buildCommand(
buildOptions.androidreleasetype ||
config.android.buildOptions.releaseType ||
'AAB',
signingtype:
buildOptions.signingtype ||
config.android.buildOptions.signingType ||
'jarsigner',
};

try {
Expand Down
1 change: 1 addition & 0 deletions ios/Capacitor/Capacitor/CAPBridgeViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import Cordova
// get the web view
let assetHandler = WebViewAssetHandler(router: router())
assetHandler.setAssetPath(configuration.appLocation.path)
assetHandler.setServerUrl(configuration.serverURL)
let delegationHandler = WebViewDelegationHandler()
prepareWebView(with: configuration, assetHandler: assetHandler, delegationHandler: delegationHandler)
view = webView
Expand Down
1 change: 1 addition & 0 deletions ios/Capacitor/Capacitor/CAPWebView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ open class CAPWebView: UIView {
private lazy var assetHandler: WebViewAssetHandler = {
let handler = WebViewAssetHandler(router: router)
handler.setAssetPath(configuration.appLocation.path)
handler.setServerUrl(bridge.config.serverURL)
return handler
}()

Expand Down
13 changes: 13 additions & 0 deletions ios/Capacitor/Capacitor/WebViewAssetHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import MobileCoreServices
// swiftlint:disable type_body_length
internal class WebViewAssetHandler: NSObject, WKURLSchemeHandler {
private var router: Router
private var serverUrl: URL?

init(router: Router) {
self.router = router
Expand All @@ -15,6 +16,10 @@ internal class WebViewAssetHandler: NSObject, WKURLSchemeHandler {
router.basePath = assetPath
}

func setServerUrl(_ serverUrl: URL?) {
self.serverUrl = serverUrl
}

func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
let startPath: String
let url = urlSchemeTask.request.url!
Expand All @@ -36,6 +41,13 @@ internal class WebViewAssetHandler: NSObject, WKURLSchemeHandler {
"Content-Type": mimeType,
"Cache-Control": "no-cache"
]

// if using live reload, then set CORS headers
if self.serverUrl != nil && self.serverUrl?.scheme != localUrl.scheme {
headers["Access-Control-Allow-Origin"] = self.serverUrl?.absoluteString
headers["Access-Control-Allow-Methods"] = "GET, OPTIONS"
}

if let rangeString = urlSchemeTask.request.value(forHTTPHeaderField: "Range"),
let totalSize = try fileUrl.resourceValues(forKeys: [.fileSizeKey]).fileSize,
isMediaExtension(pathExtension: url.pathExtension) {
Expand Down Expand Up @@ -397,6 +409,7 @@ internal class WebViewAssetHandler: NSObject, WKURLSchemeHandler {
"vsw": "application/vnd.visio",
"vsx": "application/vnd.visio",
"vtx": "application/vnd.visio",
"wasm": "application/wasm",
"wav": "audio/wav",
"wax": "audio/x-ms-wax",
"wbmp": "image/vnd.wap.wbmp",
Expand Down

0 comments on commit 1a625fc

Please sign in to comment.