expo-finance-kit
Version:
Native Expo module for Apple FinanceKit - Access financial data from Apple Card and other accounts
194 lines (180 loc) • 8.09 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.withBackgroundDeliveryExtension = void 0;
const config_plugins_1 = require("@expo/config-plugins");
const plist_1 = __importDefault(require("@expo/plist"));
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
// FinanceKit background delivery extension type
const FINANCE_KIT_EXTENSION_IDENTIFIER = 'com.apple.financekit.background-delivery';
/**
* Creates the extension target Info.plist content
*/
function getExtensionInfoPlist(extensionName) {
return plist_1.default.build({
CFBundleDevelopmentRegion: '$(DEVELOPMENT_LANGUAGE)',
CFBundleDisplayName: extensionName,
CFBundleExecutable: '$(EXECUTABLE_NAME)',
CFBundleIdentifier: '$(PRODUCT_BUNDLE_IDENTIFIER)',
CFBundleInfoDictionaryVersion: '6.0',
CFBundleName: '$(PRODUCT_NAME)',
CFBundlePackageType: '$(PRODUCT_BUNDLE_PACKAGE_TYPE)',
CFBundleShortVersionString: '$(MARKETING_VERSION)',
CFBundleVersion: '$(CURRENT_PROJECT_VERSION)',
NSExtension: {
NSExtensionPointIdentifier: FINANCE_KIT_EXTENSION_IDENTIFIER,
NSExtensionPrincipalClass: '$(PRODUCT_MODULE_NAME).BackgroundDeliveryExtension',
},
NSFinancialDataUsageDescription: 'This extension receives notifications when financial data changes to keep your app up to date.',
});
}
/**
* Creates the extension entitlements content
*/
function getExtensionEntitlements(appGroupIdentifier) {
return plist_1.default.build({
'com.apple.security.application-groups': [appGroupIdentifier],
'com.apple.developer.financekit': true,
});
}
/**
* Generates the Swift source code for the extension
*/
function generateSwiftContent(appGroupIdentifier, bundleIdentifier) {
return `import FinanceKit
import BackgroundTasks
import os.log
@available(iOS 17.4, *)
class BackgroundDeliveryExtension: NSObject {
private let logger: Logger
override init() {
// Use dynamic bundle identifier for logger
let bundleId = Bundle.main.bundleIdentifier ?? "${bundleIdentifier || 'com.expo.financekit'}"
self.logger = Logger(subsystem: bundleId, category: "BackgroundDelivery")
super.init()
logger.info("BackgroundDeliveryExtension initialized")
}
}
@available(iOS 17.4, *)
extension BackgroundDeliveryExtension: FinanceStoreDataExtension {
func financeStoreDidChange() async {
logger.info("Received finance store change notification")
// Store sync timestamp
if let appGroupURL = FileManager.default.containerURL(
forSecurityApplicationGroupIdentifier: "${appGroupIdentifier}"
) {
let syncData = ["timestamp": Date().timeIntervalSince1970]
let fileURL = appGroupURL.appendingPathComponent("last_sync.json")
if let jsonData = try? JSONSerialization.data(withJSONObject: syncData) {
try? jsonData.write(to: fileURL)
}
}
// Notify main app
let mainBundleId = Bundle.main.bundleIdentifier?.replacingOccurrences(of: ".finance-background", with: "") ?? "${bundleIdentifier || 'com.expo.financekit'}"
let notificationCenter = CFNotificationCenterGetDarwinNotifyCenter()
let notificationName = "\\(mainBundleId).dataChanged" as CFString
CFNotificationCenterPostNotification(
notificationCenter,
CFNotificationName(notificationName),
nil,
nil,
true
)
logger.info("Posted notification to main app")
}
}`;
}
/**
* Main plugin for FinanceKit extension
* Uses withDangerousMod to create extension files, which is necessary
* because we need to create new files outside the normal mod system
*/
const withBackgroundDeliveryExtension = (config, props) => {
const { appGroupIdentifier, extensionName = 'FinanceKitBackgroundExtension', extensionBundleIdentifier, } = props;
// Use dangerous mod to create extension files
config = (0, config_plugins_1.withDangerousMod)(config, [
'ios',
async (config) => {
const { platformProjectRoot } = config.modRequest;
const extensionPath = path.join(platformProjectRoot, extensionName);
// Create extension directory
if (!fs.existsSync(extensionPath)) {
fs.mkdirSync(extensionPath, { recursive: true });
}
// Write Swift file
const swiftPath = path.join(extensionPath, 'BackgroundDeliveryExtension.swift');
const swiftContent = generateSwiftContent(appGroupIdentifier, config.ios?.bundleIdentifier);
fs.writeFileSync(swiftPath, swiftContent);
// Write Info.plist
const infoPlistPath = path.join(extensionPath, 'Info.plist');
const infoPlistContent = getExtensionInfoPlist(extensionName);
fs.writeFileSync(infoPlistPath, infoPlistContent);
// Write entitlements
const entitlementsPath = path.join(extensionPath, `${extensionName}.entitlements`);
const entitlementsContent = getExtensionEntitlements(appGroupIdentifier);
fs.writeFileSync(entitlementsPath, entitlementsContent);
console.log(`✅ Created FinanceKit extension files at: ${extensionPath}`);
return config;
},
]);
// Use withXcodeProject to log instructions
// Note: Actually adding the target to Xcode requires manual steps
config = (0, config_plugins_1.withXcodeProject)(config, (config) => {
console.warn(`
⚠️ FinanceKit Extension Manual Setup Required:
Extension files have been created at: ios/${extensionName}/
To complete the setup in Xcode:
1. Open your .xcworkspace file
2. File > New > Target > App Extension
3. Select a basic App Extension template
4. Name it: ${extensionName}
5. Replace the generated files with the ones created by this plugin
6. In the extension target's Build Settings:
- Set iOS Deployment Target to 17.4
- Add the same App Group as your main app
7. In Signing & Capabilities:
- Add App Groups capability
- Add FinanceKit capability
The extension bundle ID should be: ${extensionBundleIdentifier || `${config.ios?.bundleIdentifier}.finance-background`}
`);
return config;
});
return config;
};
exports.withBackgroundDeliveryExtension = withBackgroundDeliveryExtension;