Skip to content

Commit

Permalink
Protocol Handler support
Browse files Browse the repository at this point in the history
  • Loading branch information
gstepniewski-google committed Feb 24, 2025
1 parent 9ba50ce commit 6b02d3c
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 3 deletions.
20 changes: 19 additions & 1 deletion packages/core/src/lib/TwaManifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {fetchUtils} from './FetchUtils';
import {findSuitableIcon, generatePackageId, validateNotEmpty} from './util';
import Color = require('color');
import {ConsoleLog} from './Log';
import {ShareTarget, WebManifestIcon, WebManifestJson} from './types/WebManifest';
import {ProtocolHandler, ShareTarget, WebManifestIcon, WebManifestJson} from './types/WebManifest';
import {ShortcutInfo} from './ShortcutInfo';
import {AppsFlyerConfig} from './features/AppsFlyerFeature';
import {LocationDelegationConfig} from './features/LocationDelegationFeature';
Expand Down Expand Up @@ -169,6 +169,7 @@ export class TwaManifest {
serviceAccountJsonFile: string | undefined;
additionalTrustedOrigins: string[];
retainedBundles: number[];
protocolHandlers?: ProtocolHandler[];

private static log = new ConsoleLog('twa-manifest');

Expand Down Expand Up @@ -219,6 +220,7 @@ export class TwaManifest {
this.serviceAccountJsonFile = data.serviceAccountJsonFile;
this.additionalTrustedOrigins = data.additionalTrustedOrigins || [];
this.retainedBundles = data.retainedBundles || [];
this.protocolHandlers = data.protocolHandlers;
}

/**
Expand Down Expand Up @@ -343,6 +345,7 @@ export class TwaManifest {
shareTarget: TwaManifest.verifyShareTarget(webManifestUrl, webManifest.share_target),
orientation: asOrientation(webManifest.orientation) || DEFAULT_ORIENTATION,
fullScopeUrl: fullScopeUrl.toString(),
protocolHandlers: webManifest.protocol_handlers,
});
return twaManifest;
}
Expand Down Expand Up @@ -479,6 +482,19 @@ export class TwaManifest {
oldTwaManifestJson.iconUrl!, webManifest.icons!, 'monochrome', MIN_NOTIFICATION_ICON_SIZE,
webManifestUrl);

const protocolHandlersMap = new Map<string, string>();
for (const handler of oldTwaManifest.protocolHandlers ?? []) {
protocolHandlersMap.set(handler.protocol, handler.url);
}
if (!(fieldsToIgnore.includes('protocol_handlers'))) {
for (const handler of webManifest.protocol_handlers ?? []) {
protocolHandlersMap.set(handler.protocol, handler.url);
};
}
const protocolHandlers = Array.from(protocolHandlersMap.entries()).map(([protocol, url]) => {
return {protocol, url} as ProtocolHandler;
});

const fullStartUrl: URL = new URL(webManifest['start_url'] || '/', webManifestUrl);
const fullScopeUrl: URL = new URL(webManifest['scope'] || '.', webManifestUrl);

Expand All @@ -503,6 +519,7 @@ export class TwaManifest {
maskableIconUrl: maskableIconUrl || oldTwaManifestJson.maskableIconUrl,
monochromeIconUrl: monochromeIconUrl || oldTwaManifestJson.monochromeIconUrl,
shortcuts: shortcuts,
protocolHandlers: protocolHandlers,
});
return twaManifest;
}
Expand Down Expand Up @@ -558,6 +575,7 @@ export interface TwaManifestJson {
serviceAccountJsonFile?: string;
additionalTrustedOrigins?: string[];
retainedBundles?: number[];
protocolHandlers?: ProtocolHandler[];
}

export interface SigningKeyInfo {
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/lib/types/WebManifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ export interface WebManifestShortcutJson {
icons?: Array<WebManifestIcon>;
}

export interface ProtocolHandler {
protocol: string;
url: string;
}

type WebManifestDisplayMode = 'browser' | 'minimal-ui' | 'standalone' | 'fullscreen';

export type OrientationLock = 'any' | 'natural' | 'landscape'| 'portrait' | 'portrait-primary'|
Expand Down Expand Up @@ -67,4 +72,5 @@ export interface WebManifestJson {
shortcuts?: Array<WebManifestShortcutJson>;
share_target?: ShareTarget;
orientation?: OrientationLock;
protocol_handlers?: Array<ProtocolHandler>;
}
46 changes: 44 additions & 2 deletions packages/core/src/spec/lib/TwaManifestSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,10 @@ describe('TwaManifest', () => {
'purpose': 'any',
},
],
'protocol_handlers': [{
'protocol': 'web+test-replace',
'url': 'test-format-web',
}],
};
const twaManifest = new TwaManifest({
'packageId': 'id',
Expand Down Expand Up @@ -390,12 +394,32 @@ describe('TwaManifest', () => {
'fullScopeUrl': 'https://name.github.io/',
'appVersion': '1',
'serviceAccountJsonFile': '/home/service-account.json',
'protocolHandlers': [
{
'protocol': 'web+test-replace',
'url': 'test-format-twa',
},
{
'protocol': 'web+test-keep',
'url': 'test-format-twa',
},
],
});
// The versions shouldn't change because the update happens in `cli`.
const expectedTwaManifest = new TwaManifest({
...twaManifest.toJson(),
'launcherName': 'different_name',
'display': 'fullscreen',
'protocolHandlers': [
{
'protocol': 'web+test-replace',
'url': 'test-format-web',
},
{
'protocol': 'web+test-keep',
'url': 'test-format-twa',
},
],
});
// A URL to insert as the webManifestUrl.
const url = new URL('https://name.github.io/manifest.json');
Expand All @@ -415,6 +439,10 @@ describe('TwaManifest', () => {
'purpose': 'any',
},
],
'protocol_handlers': [{
'protocol': 'web+test-replace',
'url': 'test-format-web',
}],
};
const twaManifest = new TwaManifest({
'packageId': 'id',
Expand Down Expand Up @@ -451,13 +479,27 @@ describe('TwaManifest', () => {
'fullScopeUrl': 'https://name.github.io/',
'appVersion': '1',
'serviceAccountJsonFile': '/home/service-account.json',
'protocolHandlers': [
{
'protocol': 'web+test-replace',
'url': 'test-format-twa',
},
{
'protocol': 'web+test-keep',
'url': 'test-format-twa',
},
],
});
// The versions shouldn't change because the update happens in `cli`.
const expectedTwaManifest = twaManifest;
// A URL to insert as the webManifestUrl.
const url = new URL('https://name.github.io/manifest.json');
expect(await TwaManifest.merge(['short_name', 'display'], url, webManifest, twaManifest))
.toEqual(expectedTwaManifest);
expect(await TwaManifest.merge(
['short_name', 'display', 'protocol_handlers'],
url,
webManifest,
twaManifest,
)).toEqual(expectedTwaManifest);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,15 @@
android:host="<%= additionalOrigin %>"/>
</intent-filter>
<% } %>

<% for (const protocolHandler of protocolHandlers) { %>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="<%= protocolHandler.protocol %>" />
</intent-filter>
<% } %>
</activity>

<activity android:name="com.google.androidbrowserhelper.trusted.FocusActivity" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
import android.os.Build;
import android.os.Bundle;

import java.util.HashMap;
import java.util.Map;

<% for(const imp of launcherActivity.imports) { %>
import <%= imp %>;
<% } %>
Expand Down Expand Up @@ -48,6 +51,12 @@ protected void onCreate(Bundle savedInstanceState) {
}
}

private final Map<String, String> mProtocolHandlers = new HashMap<String, String>() {{
<% for(const protocol of protocolHandlers) { %>
put("<%= protocol.protocol %>", "<%= protocol.url %>");
<% } %>
}};

@Override
protected Uri getLaunchingUrl() {
// Get the original launch Url.
Expand All @@ -57,6 +66,15 @@ protected Uri getLaunchingUrl() {
<%= code %>
<% } %>

/* Protocol Handler support */
String scheme = uri.getScheme();
if (mProtocolHandlers.containsKey(scheme)) {
String target = uri.toString().replace(scheme + "://", "");
String format = mProtocolHandlers.get(scheme);
String baseUrl = getString(R.string.launchUrl);
return Uri.parse(baseUrl + String.format(format, target));
}

return uri;
}
}

0 comments on commit 6b02d3c

Please sign in to comment.