Skip to content

Commit d4c12bc

Browse files
ebaroonirobingenz
andauthored
feat(app-shortcuts): add configuration options (#459)
* feat(app-shortcuts): add configuration options Add definitions. * feat(app-shortcuts): add configuration options Implement plugin configs on ios. * feat(app-shortcuts): add configuration options Implement plugin configs on android. * feat(app-shortcuts): add configuration options Run fmt. * feat(app-shortcuts): add configuration options Generate changeset. * Update .changeset/many-ghosts-tickle.md [skip ci] --------- Co-authored-by: Robin Genz <[email protected]>
1 parent b64ce8c commit d4c12bc

File tree

16 files changed

+245
-80
lines changed

16 files changed

+245
-80
lines changed

.changeset/many-ghosts-tickle.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@capawesome/capacitor-app-shortcuts': minor
3+
---
4+
5+
feat: add configuration option

packages/app-shortcuts/README.md

+43
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,49 @@ npm install @capawesome/capacitor-app-shortcuts
99
npx cap sync
1010
```
1111

12+
## Configuration
13+
14+
<docgen-config>
15+
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
16+
17+
| Prop | Type | Description | Since |
18+
| --------------- | ----------------------- | ------------------------------------------------------------------------------------------- | ----- |
19+
| **`shortcuts`** | <code>Shortcut[]</code> | The list of app shortcuts that should be set by default. Only available on Android and iOS. | 7.2.0 |
20+
21+
### Examples
22+
23+
In `capacitor.config.json`:
24+
25+
```json
26+
{
27+
"plugins": {
28+
"AppShortcuts": {
29+
"shortcuts": [{ id: 'feedback', title: 'Feedback' }]
30+
}
31+
}
32+
}
33+
```
34+
35+
In `capacitor.config.ts`:
36+
37+
```ts
38+
/// <reference types="@capawesome/capacitor-app-shortcuts" />
39+
40+
import { CapacitorConfig } from '@capacitor/cli';
41+
42+
const config: CapacitorConfig = {
43+
plugins: {
44+
AppShortcuts: {
45+
shortcuts: [{ id: 'feedback', title: 'Feedback' }],
46+
},
47+
},
48+
};
49+
50+
export default config;
51+
```
52+
53+
</docgen-config>
54+
1255
### iOS
1356

1457
On iOS, you must add the following to your app's `AppDelegate.swift`:

packages/app-shortcuts/android/src/main/java/io/capawesome/capacitorjs/plugins/appshortcuts/AppShortcuts.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import android.content.Context;
44
import androidx.annotation.NonNull;
5-
import androidx.annotation.Nullable;
65
import androidx.core.content.pm.ShortcutInfoCompat;
76
import androidx.core.content.pm.ShortcutManagerCompat;
87
import io.capawesome.capacitorjs.plugins.appshortcuts.classes.options.SetOptions;
@@ -16,8 +15,12 @@ public class AppShortcuts {
1615

1716
private final Context context;
1817

19-
public AppShortcuts(Context context) {
18+
public AppShortcuts(Context context, AppShortcutsConfig config) {
2019
this.context = context;
20+
List<ShortcutInfoCompat> shortcuts = config.getShortcuts();
21+
if (shortcuts != null) {
22+
ShortcutManagerCompat.setDynamicShortcuts(context, shortcuts);
23+
}
2124
}
2225

2326
public void get(@NonNull NonEmptyCallback<Result> callback) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package io.capawesome.capacitorjs.plugins.appshortcuts;
2+
3+
import androidx.annotation.NonNull;
4+
import androidx.annotation.Nullable;
5+
import androidx.core.content.pm.ShortcutInfoCompat;
6+
import java.util.List;
7+
8+
public class AppShortcutsConfig {
9+
10+
@Nullable
11+
private List<ShortcutInfoCompat> shortcuts;
12+
13+
void setShortcuts(@NonNull List<ShortcutInfoCompat> shortcuts) {
14+
this.shortcuts = shortcuts;
15+
}
16+
17+
@Nullable
18+
List<ShortcutInfoCompat> getShortcuts() {
19+
return this.shortcuts;
20+
}
21+
}

packages/app-shortcuts/android/src/main/java/io/capawesome/capacitorjs/plugins/appshortcuts/AppShortcutsHelper.java

+46
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
package io.capawesome.capacitorjs.plugins.appshortcuts;
22

3+
import android.content.Context;
4+
import android.content.Intent;
35
import androidx.annotation.NonNull;
6+
import androidx.core.content.pm.ShortcutInfoCompat;
7+
import androidx.core.graphics.drawable.IconCompat;
8+
import com.getcapacitor.Bridge;
9+
import com.getcapacitor.JSArray;
10+
import java.util.ArrayList;
411
import java.util.HashMap;
512
import java.util.Iterator;
13+
import java.util.List;
614
import org.json.JSONException;
715
import org.json.JSONObject;
816

@@ -18,4 +26,42 @@ public static HashMap<String, Object> createHashMapFromJSONObject(@NonNull JSONO
1826
}
1927
return map;
2028
}
29+
30+
@NonNull
31+
public static List<ShortcutInfoCompat> createShortcutInfoCompatList(JSArray shortcuts, Context context, Bridge bridge)
32+
throws Exception {
33+
ArrayList<ShortcutInfoCompat> shortcutInfoCompatList = new ArrayList<>();
34+
List<JSONObject> shortcutsList = shortcuts.toList();
35+
for (JSONObject shortcut : shortcutsList) {
36+
HashMap<String, Object> shortcutMap = AppShortcutsHelper.createHashMapFromJSONObject(shortcut);
37+
Object id = shortcutMap.get("id");
38+
if (id == null) {
39+
throw new Exception(AppShortcutsPlugin.ERROR_ID_MISSING);
40+
}
41+
Object title = shortcutMap.get("title");
42+
if (title == null) {
43+
throw new Exception(AppShortcutsPlugin.ERROR_TITLE_MISSING);
44+
}
45+
String description = (String) shortcutMap.get("description");
46+
Object icon = shortcutMap.get("icon");
47+
48+
ShortcutInfoCompat.Builder shortcutInfoCompat = new ShortcutInfoCompat.Builder(context, (String) id);
49+
shortcutInfoCompat.setShortLabel((String) title);
50+
if (description != null) {
51+
shortcutInfoCompat.setLongLabel(description);
52+
}
53+
shortcutInfoCompat.setIntent(
54+
new Intent(Intent.ACTION_VIEW, bridge.getIntentUri(), bridge.getContext(), bridge.getActivity().getClass()).putExtra(
55+
AppShortcutsPlugin.INTENT_EXTRA_ITEM_NAME,
56+
(String) id
57+
)
58+
);
59+
if (icon != null) {
60+
shortcutInfoCompat.setIcon(IconCompat.createWithResource(context, (int) icon));
61+
}
62+
63+
shortcutInfoCompatList.add(shortcutInfoCompat.build());
64+
}
65+
return shortcutInfoCompatList;
66+
}
2167
}

packages/app-shortcuts/android/src/main/java/io/capawesome/capacitorjs/plugins/appshortcuts/AppShortcutsPlugin.java

+20-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import android.content.Intent;
44
import androidx.annotation.NonNull;
55
import androidx.annotation.Nullable;
6+
import com.getcapacitor.JSArray;
67
import com.getcapacitor.JSObject;
78
import com.getcapacitor.Logger;
89
import com.getcapacitor.Plugin;
@@ -15,6 +16,8 @@
1516
import io.capawesome.capacitorjs.plugins.appshortcuts.interfaces.NonEmptyCallback;
1617
import io.capawesome.capacitorjs.plugins.appshortcuts.interfaces.Result;
1718
import java.util.Objects;
19+
import org.json.JSONArray;
20+
import org.json.JSONObject;
1821

1922
@CapacitorPlugin(name = "AppShortcuts")
2023
public class AppShortcutsPlugin extends Plugin {
@@ -31,8 +34,7 @@ public class AppShortcutsPlugin extends Plugin {
3134

3235
@Override
3336
public void load() {
34-
super.load();
35-
this.implementation = new AppShortcuts(getContext());
37+
this.implementation = new AppShortcuts(getContext(), getAppShortcutsConfig());
3638
}
3739

3840
@PluginMethod
@@ -128,4 +130,20 @@ protected void handleOnNewIntent(Intent intent) {
128130
}
129131
}
130132
}
133+
134+
private AppShortcutsConfig getAppShortcutsConfig() {
135+
AppShortcutsConfig config = new AppShortcutsConfig();
136+
JSONObject configJSON = getConfig().getConfigJSON();
137+
try {
138+
JSONArray shortcutsJSON = configJSON.getJSONArray("shortcuts");
139+
JSArray shortcuts = new JSArray();
140+
for (int i = 0; i < shortcutsJSON.length(); i++) {
141+
shortcuts.put(shortcutsJSON.get(i));
142+
}
143+
config.setShortcuts(AppShortcutsHelper.createShortcutInfoCompatList(shortcuts, getContext(), getBridge()));
144+
} catch (Exception e) {
145+
return config;
146+
}
147+
return config;
148+
}
131149
}

packages/app-shortcuts/android/src/main/java/io/capawesome/capacitorjs/plugins/appshortcuts/classes/options/SetOptions.java

+1-37
Original file line numberDiff line numberDiff line change
@@ -24,47 +24,11 @@ public SetOptions(@NonNull PluginCall call, @NonNull Context context, @NonNull B
2424
if (shortcuts == null) {
2525
throw new Exception(AppShortcutsPlugin.ERROR_SHORTCUTS_MISSING);
2626
}
27-
this.shortcuts = this.createShortcutInfoCompatList(shortcuts, context, bridge);
27+
this.shortcuts = AppShortcutsHelper.createShortcutInfoCompatList(shortcuts, context, bridge);
2828
}
2929

3030
@NonNull
3131
public List<ShortcutInfoCompat> getShortcuts() {
3232
return shortcuts;
3333
}
34-
35-
private List<ShortcutInfoCompat> createShortcutInfoCompatList(JSArray shortcuts, Context context, Bridge bridge) throws Exception {
36-
ArrayList<ShortcutInfoCompat> shortcutInfoCompatList = new ArrayList<>();
37-
List<JSONObject> shortcutsList = shortcuts.toList();
38-
for (JSONObject shortcut : shortcutsList) {
39-
HashMap<String, Object> shortcutMap = AppShortcutsHelper.createHashMapFromJSONObject(shortcut);
40-
Object id = shortcutMap.get("id");
41-
if (id == null) {
42-
throw new Exception(AppShortcutsPlugin.ERROR_ID_MISSING);
43-
}
44-
Object title = shortcutMap.get("title");
45-
if (title == null) {
46-
throw new Exception(AppShortcutsPlugin.ERROR_TITLE_MISSING);
47-
}
48-
String description = (String) shortcutMap.get("description");
49-
Object icon = shortcutMap.get("icon");
50-
51-
ShortcutInfoCompat.Builder shortcutInfoCompat = new ShortcutInfoCompat.Builder(context, (String) id);
52-
shortcutInfoCompat.setShortLabel((String) title);
53-
if (description != null) {
54-
shortcutInfoCompat.setLongLabel(description);
55-
}
56-
shortcutInfoCompat.setIntent(
57-
new Intent(Intent.ACTION_VIEW, bridge.getIntentUri(), bridge.getContext(), bridge.getActivity().getClass()).putExtra(
58-
AppShortcutsPlugin.INTENT_EXTRA_ITEM_NAME,
59-
(String) id
60-
)
61-
);
62-
if (icon != null) {
63-
shortcutInfoCompat.setIcon(IconCompat.createWithResource(context, (int) icon));
64-
}
65-
66-
shortcutInfoCompatList.add(shortcutInfoCompat.build());
67-
}
68-
return shortcutInfoCompatList;
69-
}
7034
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
{
22
"appId": "com.example.plugin",
33
"appName": "example",
4-
"bundledWebRuntime": false,
5-
"webDir": "dist"
4+
"webDir": "dist",
5+
"plugins": {
6+
"AppShortcuts": {
7+
"shortcuts": [{ "id": "feedback", "title": "Feedback" }]
8+
}
9+
}
610
}

packages/app-shortcuts/example/ios/App/App/Info.plist

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<key>CFBundleDevelopmentRegion</key>
66
<string>en</string>
77
<key>CFBundleDisplayName</key>
8-
<string>example</string>
8+
<string>example</string>
99
<key>CFBundleExecutable</key>
1010
<string>$(EXECUTABLE_NAME)</string>
1111
<key>CFBundleIdentifier</key>

packages/app-shortcuts/ios/Plugin.xcodeproj/project.pbxproj

+8
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
50ADFFA42020D75100D50D53 /* Capacitor.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFFA52020D75100D50D53 /* Capacitor.framework */; };
1616
50E1A94820377CB70090CE1A /* AppShortcutsPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E1A94720377CB70090CE1A /* AppShortcutsPlugin.swift */; };
1717
7C23F4112D1434F80062E466 /* ClickEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C23F4102D1434F00062E466 /* ClickEvent.swift */; };
18+
7CA40E142D8A110500FE1CC7 /* AppShortcutsConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CA40E132D8A10FA00FE1CC7 /* AppShortcutsConfig.swift */; };
1819
7CC437E92D0CCF94007934A8 /* GetResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CC437E82D0CCF7A007934A8 /* GetResult.swift */; };
1920
7CC437EC2D0CE897007934A8 /* SetOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CC437EB2D0CE892007934A8 /* SetOptions.swift */; };
2021
7CC437F52D0E3096007934A8 /* CustomError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CC437F42D0E3096007934A8 /* CustomError.swift */; };
2122
7CC437F82D0E30A0007934A8 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CC437F62D0E30A0007934A8 /* Result.swift */; };
23+
7CC64AA22D8AB6A500DC7F80 /* AppShortcutsPluginHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CC64AA12D8AB69900DC7F80 /* AppShortcutsPluginHelper.swift */; };
2224
/* End PBXBuildFile section */
2325

2426
/* Begin PBXContainerItemProxy section */
@@ -43,10 +45,12 @@
4345
50E1A94720377CB70090CE1A /* AppShortcutsPlugin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppShortcutsPlugin.swift; sourceTree = "<group>"; };
4446
5E23F77F099397094342571A /* Pods-Plugin.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Plugin/Pods-Plugin.debug.xcconfig"; sourceTree = "<group>"; };
4547
7C23F4102D1434F00062E466 /* ClickEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClickEvent.swift; sourceTree = "<group>"; };
48+
7CA40E132D8A10FA00FE1CC7 /* AppShortcutsConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppShortcutsConfig.swift; sourceTree = "<group>"; };
4649
7CC437E82D0CCF7A007934A8 /* GetResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetResult.swift; sourceTree = "<group>"; };
4750
7CC437EB2D0CE892007934A8 /* SetOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetOptions.swift; sourceTree = "<group>"; };
4851
7CC437F42D0E3096007934A8 /* CustomError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomError.swift; sourceTree = "<group>"; };
4952
7CC437F62D0E30A0007934A8 /* Result.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Result.swift; sourceTree = "<group>"; };
53+
7CC64AA12D8AB69900DC7F80 /* AppShortcutsPluginHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppShortcutsPluginHelper.swift; sourceTree = "<group>"; };
5054
91781294A431A2A7CC6EB714 /* Pods-Plugin.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.release.xcconfig"; path = "Pods/Target Support Files/Pods-Plugin/Pods-Plugin.release.xcconfig"; sourceTree = "<group>"; };
5155
96ED1B6440D6672E406C8D19 /* Pods-PluginTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.debug.xcconfig"; sourceTree = "<group>"; };
5256
F65BB2953ECE002E1EF3E424 /* Pods-PluginTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.release.xcconfig"; sourceTree = "<group>"; };
@@ -98,6 +102,8 @@
98102
50ADFF8A201F53D600D50D53 /* Plugin */ = {
99103
isa = PBXGroup;
100104
children = (
105+
7CC64AA12D8AB69900DC7F80 /* AppShortcutsPluginHelper.swift */,
106+
7CA40E132D8A10FA00FE1CC7 /* AppShortcutsConfig.swift */,
101107
7CC437F72D0E30A0007934A8 /* Protocols */,
102108
7CC437F32D0E308D007934A8 /* Enums */,
103109
7CC437E62D0CCF63007934A8 /* Classes */,
@@ -367,6 +373,8 @@
367373
50E1A94820377CB70090CE1A /* AppShortcutsPlugin.swift in Sources */,
368374
7CC437E92D0CCF94007934A8 /* GetResult.swift in Sources */,
369375
2F98D68224C9AAE500613A4C /* AppShortcuts.swift in Sources */,
376+
7CA40E142D8A110500FE1CC7 /* AppShortcutsConfig.swift in Sources */,
377+
7CC64AA22D8AB6A500DC7F80 /* AppShortcutsPluginHelper.swift in Sources */,
370378
7CC437F82D0E30A0007934A8 /* Result.swift in Sources */,
371379
7C23F4112D1434F80062E466 /* ClickEvent.swift in Sources */,
372380
);

packages/app-shortcuts/ios/Plugin/AppShortcuts.swift

+10
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@ import Foundation
22
import UIKit
33

44
@objc public class AppShortcuts: NSObject {
5+
let config: AppShortcutsConfig
6+
7+
public init(_ config: AppShortcutsConfig) {
8+
self.config = config
9+
super.init()
10+
if let configShortcuts = self.config.shortcuts {
11+
self.set(shortcuts: configShortcuts, completion: { _ in })
12+
}
13+
}
14+
515
@objc public func get(completion: @escaping (Result) -> Void) {
616
let application = UIApplication.shared
717

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import UIKit
2+
3+
public struct AppShortcutsConfig {
4+
var shortcuts: [UIApplicationShortcutItem]?
5+
}

0 commit comments

Comments
 (0)