Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev/john/native preferences #636

Merged
merged 5 commits into from
Dec 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions how-to/workspace-platform-starter/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## v16

- Improved launchPreference so that now args for a native app (app asset or external) can be specified via launchPreference. Launch preference can also be configured to allow args to be specified dynamically when the launch request is made. Please see [how to define app launch preference](./docs/how-to-define-app-launch-preference.md).
- Improved launchPreference so additional options such as url, interop, customData can be specified. Modules can now pass a launchPreference when launching an app by appId. They can see if the app supports being updated by getting the app by id and checking for the updatable setting under launchPreference.options. Only inline-view/view and inline-window/window support updatable launch preferences. Please see [how to define app launch preference](./docs/how-to-define-app-launch-preference.md).
- Added support for Snap, enable by setting `customSettings.snapProvider.enabled` to true. Configure the `customSettings.snapProvider.serverAssetInfo` to point to the `SNAP_ASSET_URL`. Enable the Snap debugging window by setting `customSettings.snapProvider.showDebugWindow` to true.
- Added new module type `content-creation`, these modules can be used to define content creation rules and handle the associated events. Modules are added in `customSettings.contentCreationProvider` section in manifest.
Expand Down
56 changes: 43 additions & 13 deletions how-to/workspace-platform-starter/client/src/framework/launch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,15 @@ export async function launch(
switch (app.manifestType) {
case MANIFEST_TYPES.External.id:
case MANIFEST_TYPES.InlineExternal.id: {
const platformIdentity = await launchExternal(app);
const platformIdentity = await launchExternal(app, undefined, launchPreference);
if (platformIdentity) {
platformAppIdentities.push(platformIdentity);
}
break;
}
case MANIFEST_TYPES.Appasset.id:
case MANIFEST_TYPES.InlineAppAsset.id: {
const platformIdentity = await launchAppAsset(app);
const platformIdentity = await launchAppAsset(app, undefined, launchPreference);
if (platformIdentity) {
platformAppIdentities.push(platformIdentity);
}
Expand Down Expand Up @@ -846,11 +846,13 @@ async function launchSnapshot(snapshotApp: PlatformApp): Promise<PlatformAppIden
* Launch an app asset for the platform app.
* @param appAssetApp The app to launch app asset view for.
* @param instanceId Provide an instance id for the app being launched.
* @param launchPreference Optional custom launch preferences
* @returns The identities of the snapshot parts launched.
*/
export async function launchAppAsset(
appAssetApp: PlatformApp,
instanceId?: string
instanceId?: string,
launchPreference?: UpdatableLaunchPreference
): Promise<PlatformAppIdentifier | undefined> {
const options: OpenFin.ExternalProcessRequestType = {};
logger.info(`Request to launch app asset app of type ${appAssetApp.manifestType}`);
Expand Down Expand Up @@ -881,7 +883,7 @@ export async function launchAppAsset(
}
try {
logger.info(`Launching app asset with appId: ${appAssetApp.appId} with the following options:`, options);
const identity = await launchExternalProcess(appAssetApp, options, instanceId);
const identity = await launchExternalProcess(appAssetApp, options, instanceId, launchPreference);
logger.info(
`External app with appId: ${appAssetApp.appId} launched with the following identity`,
identity
Expand All @@ -896,11 +898,13 @@ export async function launchAppAsset(
* Launch an external for the platform app.
* @param externalApp The app to launch external view for.
* @param instanceId Provide an instance id for the app being launched.
* @param launchPreference Optional custom launch preferences
* @returns The identities of the app parts launched.
*/
export async function launchExternal(
externalApp: PlatformApp,
instanceId?: string
instanceId?: string,
launchPreference?: UpdatableLaunchPreference
): Promise<PlatformAppIdentifier | undefined> {
let options: OpenFin.ExternalProcessRequestType = {};
logger.info(`Request to external app of type ${externalApp.manifestType}`);
Expand All @@ -922,7 +926,7 @@ export async function launchExternal(
`Launching external app asset with appId: ${externalApp.appId} with the following options:`,
options
);
const identity = await launchExternalProcess(externalApp, options, instanceId);
const identity = await launchExternalProcess(externalApp, options, instanceId, launchPreference);
logger.info(
`External app with appId: ${externalApp.appId} launched with the following identity`,
identity
Expand All @@ -938,18 +942,47 @@ export async function launchExternal(
* @param app The app being launched.
* @param options The launch options.
* @param instanceId Provide an instance id for the app being launched.
* @param launchPreference Optional custom launch preferences
* @returns The identity of the process.
*/
async function launchExternalProcess(
app: PlatformApp,
options: OpenFin.ExternalProcessRequestType,
instanceId?: string
instanceId?: string,
launchPreference?: UpdatableLaunchPreference
): Promise<PlatformAppIdentifier> {
const nativeOptions = app.launchPreference?.options as NativeLaunchOptions;

const hasPath = isStringValue(options.path);

let identity: PlatformAppIdentifier | undefined;

let args: string[] | undefined;

if (nativeOptions?.type === "native") {
if (
launchPreference?.options?.type === "native" &&
Array.isArray(nativeOptions?.updatable) &&
nativeOptions.updatable.length > 0
) {
for (const option of nativeOptions.updatable) {
if (option.name === "arguments" && Array.isArray(launchPreference.options.native?.arguments)) {
args = launchPreference.options.native?.arguments;
logger.debug(`Using passed launch preference for the args for app ${app.appId}`, args);
}
}
}
if (isEmpty(args) && Array.isArray(nativeOptions?.native?.arguments)) {
args = nativeOptions.native?.arguments;
logger.debug(`Using app definition based args for app ${app.appId}`, args);
}
}
if (isEmpty(args) && isStringValue(options.arguments)) {
args = [options.arguments];
} else if (isEmpty(args)) {
args = [];
}

if (
snapProvider.isEnabled() &&
nativeOptions?.type === "native" &&
Expand All @@ -973,11 +1006,6 @@ async function launchExternalProcess(
instanceId = app.instanceMode === "single" ? app.appId : randomUUID();
}

let args = nativeOptions.snap?.args;
if (!isStringValue(args) && isStringValue(options.arguments)) {
args = [options.arguments];
}

const launchIdentity = await snapProvider.launchApp(
path,
args,
Expand All @@ -1001,7 +1029,9 @@ async function launchExternalProcess(
}

if (isEmpty(identity)) {
const launchIdentity = await fin.System.launchExternalProcess(options);
const clonedOptions = objectClone(options);
clonedOptions.arguments = args.join(" ");
const launchIdentity = await fin.System.launchExternalProcess(clonedOptions);
identity = { ...launchIdentity, appId: app.appId };
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,14 +163,24 @@ export interface Preference<T = unknown> {
/**
* What setting is updatable?
*/
name: ViewPreferenceName | WebPreferenceName;
name: ViewPreferenceName | WebPreferenceName | NativePreferenceName;

/**
* Is there a constraint that the platform can apply?
*/
constraint?: T;
}

/**
* Which Launch Options are updatable and are there any constraints
*/
export interface NativePreference<T = never> extends Preference<T> {
/**
* What setting is updatable?
*/
name: NativePreferenceName;
}

/**
* Which Launch Options are updatable and are there any constraints
*/
Expand All @@ -191,6 +201,11 @@ export interface ViewPreferenceUrl extends ViewPreference<PreferenceConstraintUr
name: "url" | "host-options";
}

/**
* A list of native related settings that can be updated.
*/
export type NativePreferenceName = "arguments";

/**
* A list of web related settings that can be updated.
*/
Expand Down Expand Up @@ -218,6 +233,22 @@ export interface NativeLaunchOptions extends LaunchOptions {
* If specified it indicates the native app should be included when snapping.
*/
snap?: SnapLaunchOptions;

/**
* Launch Preferences related to native apps
*/
native?: {
/**
* Arguments are set as an array for compatibility with appAssets, launchExternalProcess and Snap.
*/
arguments?: string[];
};

/**
* What can be specified when launching a native app. This is an array of named types to reflect the properties you are happy to be specified.
* By default nothing can be set outside of the app definition when launching the app.
*/
updatable?: NativePreference[];
}

/**
Expand Down Expand Up @@ -267,12 +298,6 @@ export interface HostLaunchOptions {
* Additional options that apply to the app when used in a snap context
*/
export interface SnapLaunchOptions {
/**
* Snap requires args as a string array, not a single string like in app assets.
* So we provide the ability to include them here.
*/
args?: string[];

/**
* The strategy for launching and locating the application.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,12 +145,21 @@ export interface Preference<T = unknown> {
/**
* What setting is updatable?
*/
name: ViewPreferenceName | WebPreferenceName;
name: ViewPreferenceName | WebPreferenceName | NativePreferenceName;
/**
* Is there a constraint that the platform can apply?
*/
constraint?: T;
}
/**
* Which Launch Options are updatable and are there any constraints
*/
export interface NativePreference<T = never> extends Preference<T> {
/**
* What setting is updatable?
*/
name: NativePreferenceName;
}
/**
* Which Launch Options are updatable and are there any constraints
*/
Expand All @@ -169,6 +178,10 @@ export interface ViewPreferenceUrl extends ViewPreference<PreferenceConstraintUr
*/
name: "url" | "host-options";
}
/**
* A list of native related settings that can be updated.
*/
export type NativePreferenceName = "arguments";
/**
* A list of web related settings that can be updated.
*/
Expand All @@ -193,6 +206,20 @@ export interface NativeLaunchOptions extends LaunchOptions {
* If specified it indicates the native app should be included when snapping.
*/
snap?: SnapLaunchOptions;
/**
* Launch Preferences related to native apps
*/
native?: {
/**
* Arguments are set as an array for compatibility with appAssets, launchExternalProcess and Snap.
*/
arguments?: string[];
};
/**
* What can be specified when launching a native app. This is an array of named types to reflect the properties you are happy to be specified.
* By default nothing can be set outside of the app definition when launching the app.
*/
updatable?: NativePreference[];
}
/**
* Additional options that apply to the host of the content
Expand Down Expand Up @@ -233,11 +260,6 @@ export interface HostLaunchOptions {
* Additional options that apply to the app when used in a snap context
*/
export interface SnapLaunchOptions {
/**
* Snap requires args as a string array, not a single string like in app assets.
* So we provide the ability to include them here.
*/
args?: string[];
/**
* The strategy for launching and locating the application.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,22 @@ export interface NativeLaunchOptions extends LaunchOptions {
* If specified it indicates the native app should be included when snapping.
*/
snap?: SnapLaunchOptions;

/**
* Launch Preferences related to native apps
*/
native?: {
/**
* Arguments are set as an array for compatibility with appAssets, launchExternalProcess and Snap.
*/
arguments?: string[];
};

/**
* What can be specified when launching a native app. This is an array of named types to reflect the properties you are happy to be specified.
* By default nothing can be set outside of the app definition when launching the app.
*/
updatable?: NativePreference[];
}
```

Expand All @@ -291,6 +307,33 @@ These settings are used to specify snap specific settings which are used by the

To find out more about these settings please visit the [how to configure snap](./how-to-configure-snap.md).

#### Native settings

Native settings let you specify an array of arguments that will be put together and passed to the native application that is being launched. It will override the default arguments that may have been specified.

#### Updatable Native Options

An app directory is the golden source for the description of an app. A platform can launch application in many ways but it may want to restrict what can be dynamically changed when launching an app and this is where the updatable setting comes in. This is an array of options that contain the name of the setting that can be configured and an optional array of constraints that should be checked before trying to apply the update (if applicable).

```javascript
/**
* Which Launch Options are updatable and are there any constraints
*/
export interface NativePreference<T = never> extends Preference<T> {
/**
* What setting is updatable?
*/
name: NativePreferenceName;
}

/**
* A list of native related settings that can be updated.
*/
export type NativePreferenceName = "arguments";
```

You can see that you can have an updatable array with an object that specify that you want arguments to be dynamically updatable. Without that setting you can still override the arguments but only through the launchPreference within the app definition.

## Using Launch Preferences from a module

When building a module it may have permission to get and launch applications. These helper functions are passed in a helper object when the module is initialized. See [How to add a module](./how-to-add-a-module.md).
Expand Down
Loading
Loading