Skip to content
Open
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
26 changes: 21 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
<img src="https://img.shields.io/npm/dt/expo-check-installed-apps?color=darkgreen&style=flat-square&logo=npm" alt="npm downloads"/>
</div>


A **config plugin** for Expo to check for the existence of installed apps on Android and iOS.

> **Note:** This library supports **Expo SDK 51 and above**.
Expand All @@ -22,6 +21,7 @@ A **config plugin** for Expo to check for the existence of installed apps on And
- [Manual Configuration](#manual-configuration)
- [API Documentation](#api-documentation)
- [`checkInstalledApps`](#checkinstalledapps)
- [`checkInstalledAppsSync`](#checkinstalledappssync)
- [Example Usage](#example-usage)
- [Contributing](#contributing)
- [Support the Project](#support-the-project)
Expand Down Expand Up @@ -107,20 +107,36 @@ Add the URL schemes to your `Info.plist`:

### `checkInstalledApps`

Checks whether specific apps are installed on the user's device.
Checks asynchronously whether specific apps are installed on the user's device.

#### Parameters

- **`packageNames`** (`Array<string>`):
- **`packageNames`** (`Array<string>`):
An array of package names (for Android) or URL schemes (for iOS) to check.

#### Returns

- **`Promise<Record<string, boolean>>`**:
- **`Promise<Record<string, boolean>>`**:
Resolves to an object where keys are package names or URL schemes, and values are booleans:
- `true`: App is installed.
- `false`: App is not installed.

### `checkInstalledAppsSync`

Checks synchronously whether specific apps are installed on the user's device.

#### Parameters

- **`packageNames`** (`Array<string>`):
An array of package names (for Android) or URL schemes (for iOS) to check.

#### Returns

- **`Record<string, boolean>`**:
Returns an object where keys are package names or URL schemes, and values are booleans:
- `true`: App is installed.
- `false`: App is not installed.

---

## Example Usage
Expand Down Expand Up @@ -167,5 +183,5 @@ Contributions are welcome!

If you find this library helpful, consider supporting it:

[![Buy Me a Coffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-Support%20Me-orange?logo=buymeacoffee)](https://www.buymeacoffee.com/mantu.728)
[![Buy Me a Coffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-Support%20Me-orange?logo=buymeacoffee)](https://www.buymeacoffee.com/mantu.728)
[![Donate via PayPal](https://img.shields.io/badge/Donate-PayPal-blue?logo=paypal)](https://paypal.me/Monty728)
Original file line number Diff line number Diff line change
Expand Up @@ -32,24 +32,32 @@ class ExpoCheckInstalledAppsModule : Module() {
// is by default dispatched on the different thread than the JavaScript runtime runs on.
AsyncFunction("setValueAsync") { value: String ->
// Send an event to JavaScript.
sendEvent("onChange", mapOf(
"value" to value
))
sendEvent(
"onChange", mapOf(
"value" to value
)
)
}

// An asynchronous function that takes a list of package names and returns their installation status.
AsyncFunction("checkAppsInstalled") { packageNames: Array<String>, promise: Promise ->
// Call the function to check installed apps and return the result
checkAppsInstalled(packageNames, promise)
val result = checkAppsInstalled(packageNames)
promise.resolve(result)
}

// A synchronous function that takes a list of package names and returns their installation status.
Function("checkAppsInstalledSync") { packageNames: Array<String> ->
// Call the function to check installed apps and return the result
checkAppsInstalled(packageNames)
}
}

private val context
get() = requireNotNull(appContext.reactContext)

// Function to check if multiple apps are installed and resolve the promise with the result
private fun checkAppsInstalled(packageNames: Array<String>, promise: Promise) {
private fun checkAppsInstalled(packageNames: Array<String>): MutableMap<String, Boolean> {
val pm: PackageManager = context.packageManager
val result = mutableMapOf<String, Boolean>()

Expand All @@ -63,7 +71,6 @@ class ExpoCheckInstalledAppsModule : Module() {
}
}

// Resolve the promise with the map of package names and installation statuses
promise.resolve(result)
return result;
}
}
9 changes: 7 additions & 2 deletions example/App.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { Platform, StyleSheet, Text, View } from "react-native";
import { checkInstalledApps, hello } from "expo-check-installed-apps";
import {
checkInstalledApps,
hello,
checkInstalledAppsSync,
} from "expo-check-installed-apps";
import { useEffect, useState } from "react";

export default function App() {
const [result, setResult] = useState({});
const packageNames: string[] =
Platform.select({
android: [
Expand All @@ -14,6 +17,8 @@ export default function App() {
ios: ["fb://", "twitter://"],
}) || [];

const [result, setResult] = useState(checkInstalledAppsSync(packageNames));

useEffect(() => {
const checkInstalled = async () => {
const checkInstalledAppsResult = await checkInstalledApps(packageNames);
Expand Down
6 changes: 3 additions & 3 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ PODS:
- ExpoModulesCore
- ExpoAsset (10.0.10):
- ExpoModulesCore
- ExpoCheckInstalledApps (0.2.1):
- ExpoCheckInstalledApps (0.2.9):
- ExpoModulesCore
- ExpoFileSystem (17.0.1):
- ExpoModulesCore
Expand Down Expand Up @@ -1407,7 +1407,7 @@ SPEC CHECKSUMS:
EXConstants: 409690fbfd5afea964e5e9d6c4eb2c2b59222c59
Expo: 9b6666ef2fedcfc89c5b9be2aa1ce12b81f9e7f5
ExpoAsset: 323700f291684f110fb55f0d4022a3362ea9f875
ExpoCheckInstalledApps: d1181123d716af565c50ce02e2633db3c91056f0
ExpoCheckInstalledApps: 870cfbbe26fc1fffd561b92686d352271ad50018
ExpoFileSystem: 80bfe850b1f9922c16905822ecbf97acd711dc51
ExpoFont: 00756e6c796d8f7ee8d211e29c8b619e75cbf238
ExpoKeepAwake: 3b8815d9dd1d419ee474df004021c69fdd316d08
Expand Down Expand Up @@ -1468,4 +1468,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: b4fee261fb7f6e5b531dd61914c93496c7af3ed4

COCOAPODS: 1.14.3
COCOAPODS: 1.16.2
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@
TargetAttributes = {
13B07F861A680F5B00A75B9A = {
LastSwiftMigration = 1250;
DevelopmentTeam = "8T93V936A6";
ProvisioningStyle = Automatic;
};
};
};
Expand Down Expand Up @@ -349,12 +351,15 @@
);
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
PRODUCT_BUNDLE_IDENTIFIER = expo.modules.checkinstalledapps.example;
PRODUCT_NAME = "expocheckinstalledappsexample";
PRODUCT_NAME = expocheckinstalledappsexample;
SWIFT_OBJC_BRIDGING_HEADER = "expocheckinstalledappsexample/expocheckinstalledappsexample-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
DEVELOPMENT_TEAM = "8T93V936A6";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
};
name = Debug;
};
Expand All @@ -377,11 +382,14 @@
);
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
PRODUCT_BUNDLE_IDENTIFIER = expo.modules.checkinstalledapps.example;
PRODUCT_NAME = "expocheckinstalledappsexample";
PRODUCT_NAME = expocheckinstalledappsexample;
SWIFT_OBJC_BRIDGING_HEADER = "expocheckinstalledappsexample/expocheckinstalledappsexample-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
DEVELOPMENT_TEAM = "8T93V936A6";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
};
name = Release;
};
Expand Down
33 changes: 21 additions & 12 deletions ios/ExpoCheckInstalledAppsModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,26 @@ public class ExpoCheckInstalledAppsModule: Module {
}

AsyncFunction("checkAppsInstalled") { (packageNames: [String], promise: Promise) in
var result: [String: Bool] = [:]

for packageName in packageNames {
if let url = URL(string: packageName), UIApplication.shared.canOpenURL(url) {
result[packageName] = true
} else {
result[packageName] = false
}
}

promise.resolve(result)
}
var result = checkAppsInstalled(packageNames: packageNames)
promise.resolve(result)
}

Function("checkAppsInstalledSync") { (packageNames: [String]) in
return checkAppsInstalled(packageNames: packageNames)
}
}

func checkAppsInstalled(packageNames: [String]) -> [String: Bool] {
var result: [String: Bool] = [:]

for packageName in packageNames {
if let url = URL(string: packageName), UIApplication.shared.canOpenURL(url) {
result[packageName] = true
} else {
result[packageName] = false
}
}

return result
}
}
6 changes: 6 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ export async function checkInstalledApps(
return ExpoCheckInstalledAppsModule.checkAppsInstalled(packageNames);
}

export function checkInstalledAppsSync(
packageNames: Array<string>
): Record<string, boolean> {
return ExpoCheckInstalledAppsModule.checkAppsInstalledSync(packageNames);
}

export async function setValueAsync(value: string) {
return await ExpoCheckInstalledAppsModule.setValueAsync(value);
}