Skip to content

Commit

Permalink
[ios][application] Migrate to Expo Modules API (#24871)
Browse files Browse the repository at this point in the history
  • Loading branch information
reichhartd authored and marklawlor committed Oct 30, 2023
1 parent 59c9c19 commit 8faf61c
Show file tree
Hide file tree
Showing 23 changed files with 207 additions and 263 deletions.
1 change: 1 addition & 0 deletions packages/expo-application/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

### 🎉 New features

- Migrate iOS module to Expo modules API. ([#24871](https://github.com/expo/expo/pull/24871) by [@reichhartd](https://github.com/reichhartd))
- Android module is now written using the Sweet API. ([#22395](https://github.com/expo/expo/pull/22585) by [@fobos531](https://github.com/fobos531))

### 🐛 Bug fixes
Expand Down
11 changes: 2 additions & 9 deletions packages/expo-application/build/Application.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/expo-application/build/Application.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 3 additions & 11 deletions packages/expo-application/build/Application.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/expo-application/build/Application.js.map

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions packages/expo-application/build/Application.types.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/expo-application/build/Application.types.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions packages/expo-application/build/Application.types.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/expo-application/build/Application.types.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/expo-application/build/ExpoApplication.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/expo-application/build/ExpoApplication.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions packages/expo-application/expo-module.config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"name": "expo-application",
"platforms": ["ios", "android"],
"ios": {
"modules": ["ApplicationModule"]
},
"android": {
"modules": ["expo.modules.application.ApplicationModule"]
}
Expand Down
19 changes: 19 additions & 0 deletions packages/expo-application/ios/ApplicationExceptions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import ExpoModulesCore

internal class UrlDocumentDirectoryException: Exception {
override var reason: String {
"Unable to get url for document directory"
}
}

internal class InstallationTimeException: Exception {
override var reason: String {
"Unable to get installation time of this application"
}
}

internal class DateCastException: Exception {
override var reason: String {
"Invalid date format"
}
}
48 changes: 48 additions & 0 deletions packages/expo-application/ios/ApplicationModule.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2018-present 650 Industries. All rights reserved.
import ExpoModulesCore

public class ApplicationModule: Module {
public func definition() -> ModuleDefinition {
Name("ExpoApplication")

Constants {
let infoPlist = Bundle.main.infoDictionary
return [
"applicationName": infoPlist?["CFBundleDisplayName"],
"applicationId": infoPlist?["CFBundleIdentifier"],
"nativeApplicationVersion": infoPlist?["CFBundleShortVersionString"],
"nativeBuildVersion": infoPlist?["CFBundleVersion"]
]
}

AsyncFunction("getIosIdForVendorAsync") { () -> String? in
return UIDevice.current.identifierForVendor?.uuidString
}

AsyncFunction("getInstallationTimeAsync") { () -> Double in
guard let urlToDocumentsFolder = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last else {
throw UrlDocumentDirectoryException()
}

do {
let fileAttributes = try FileManager.default.attributesOfItem(atPath: urlToDocumentsFolder.path)
if let installDate = fileAttributes[FileAttributeKey.creationDate] as? Date {
return installDate.timeIntervalSince1970 * 1000
}
throw DateCastException()
} catch {
throw InstallationTimeException()
}
}

AsyncFunction("getApplicationReleaseTypeAsync") { () -> Int in
let mainProvisioningProfile = ApplicationModuleProvisioningProfile.mainProvisioningProfile
return mainProvisioningProfile.appReleaseType().rawValue
}

AsyncFunction("getPushNotificationServiceEnvironmentAsync") { () -> String? in
let mainProvisioningProfile = ApplicationModuleProvisioningProfile.mainProvisioningProfile
return mainProvisioningProfile.notificationServiceEnvironment()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright 2015-present 650 Industries. All rights reserved.
import ExpoModulesCore

class ApplicationModuleProvisioningProfile {
private let plist = readProvisioningProfilePlist()
static let mainProvisioningProfile = ApplicationModuleProvisioningProfile()

func notificationServiceEnvironment() -> String? {
guard let plist = plist else {
return nil
}

let entitlements = plist["Entitlements"] as? [String: Any]
return entitlements?["aps-environment"] as? String
}

func appReleaseType() -> AppReleaseType {
guard let provisioningPath = Bundle.main.path(forResource: "embedded", ofType: "mobileprovision") else {
#if targetEnvironment(simulator)
return .simulator
#else
return .appStore
#endif
}

guard let mobileProvision = plist else {
return .unknown
}

if let provisionsAllDevices = mobileProvision["ProvisionsAllDevices"] as? Bool, provisionsAllDevices {
return .enterprise
}
if let provisionedDevices = mobileProvision["ProvisionedDevices"] as? [String], !provisionedDevices.isEmpty {
let entitlements = mobileProvision["Entitlements"] as? [String: Any]
if let getTaskAllow = entitlements?["get-task-allow"] as? Bool, getTaskAllow {
return .dev
}
return .adHoc
}
return .appStore
}

private static func readProvisioningProfilePlist() -> [String: Any]? {
guard let profilePath = Bundle.main.path(forResource: "embedded", ofType: "mobileprovision") else {
return nil
}

do {
let profileString = try String(contentsOfFile: profilePath, encoding: .ascii)
guard let plistStart = profileString.range(of: "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"),
let plistEnd = profileString.range(of: "</plist>") else {
return nil
}

let plistString = String(profileString[plistStart.lowerBound..<plistEnd.upperBound])
if let plistData = plistString.data(using: .utf8) {
return try PropertyListSerialization.propertyList(from: plistData, options: [], format: nil) as? [String: Any]
}
log.error("Failed to convert plistString to UTF-8 encoded data object.")
return nil
} catch {
log.error("Error reading provisioning profile: \(error.localizedDescription)")
return nil
}
}
}

enum AppReleaseType: Int, Enumerable {
case unknown = 0
case simulator = 1
case enterprise = 2
case dev = 3
case adHoc = 4
case appStore = 5
}
8 changes: 0 additions & 8 deletions packages/expo-application/ios/EXApplication/EXApplication.h

This file was deleted.

57 changes: 0 additions & 57 deletions packages/expo-application/ios/EXApplication/EXApplication.m

This file was deleted.

This file was deleted.

0 comments on commit 8faf61c

Please sign in to comment.