Skip to content

Commit

Permalink
feat: create expo config plugin (#205)
Browse files Browse the repository at this point in the history
* feat: create expo config plugin
* chore: update README for expo example
* chore: update jest config to avoid run test in lib
  • Loading branch information
giautm committed Feb 23, 2022
1 parent 40a9866 commit d44e360
Show file tree
Hide file tree
Showing 30 changed files with 5,704 additions and 370 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Expand Up @@ -43,3 +43,6 @@ lib/

# vscode
.vscode

# Keep expo plugin build code
!plugin/build
50 changes: 50 additions & 0 deletions README.md
Expand Up @@ -689,6 +689,56 @@ const infoRequest = new GraphRequest(
new GraphRequestManager().addRequest(infoRequest).start();
```
## Expo installation
> This package cannot be used in the "Expo Go" app because [it requires custom native code](https://docs.expo.io/workflow/customizing/).
After installing this npm package, add the [config plugin](https://docs.expo.io/guides/config-plugins/) to the [`plugins`](https://docs.expo.io/versions/latest/config/app/#plugins) array of your `app.json` or `app.config.js`:
```json
{
"expo": {
"plugins": ["react-native-fbsdk-next"]
}
}
```
Next, rebuild your app as described in the ["Adding custom native code"](https://docs.expo.io/workflow/customizing/) guide.
### API
The plugin provides props for extra customization. Every time you change the props or plugins, you'll need to rebuild (and `prebuild`) the native app. If no extra properties are added, defaults will be used.
- `appID` (_string_): Facebook Application ID.
- `displayName` (_string_): Application Name.
- `clientToken` (_string_): Client Token.
- `iosUserTrackingPermission` (_string_): iOS User Tracking Permission. Defaults `This identifier will be used to deliver personalized ads to you.`.
- `advertiserIDCollectionEnabled` (_boolean_): Enable advertiser ID collection. Default `false`.
- `autoLogAppEventsEnabled` (_boolean_): Default `false`.
- `isAutoInitEnabled` (_boolean_): Default `false`.
#### Example
```json
{
"expo": {
"plugins": [
[
"react-native-fbsdk-next",
{
"appID": "48127127xxxxxxxx",
"clientToken": "c5078631e4065b60d7544a95xxxxxxxx",
"displayName": "RN SDK Demo",
"advertiserIDCollectionEnabled": false,
"autoLogAppEventsEnabled": false,
"isAutoInitEnabled": true
}
]
]
}
}
```
## Example app
To run the example app, you'll first need to setup the environment:
```
Expand Down
1 change: 1 addition & 0 deletions app.plugin.js
@@ -0,0 +1 @@
module.exports = require('./plugin/build/withFacebook');
10 changes: 10 additions & 0 deletions expo-module.config.json
@@ -0,0 +1,10 @@
{
"platforms": [
"ios"
],
"ios": {
"appDelegateSubscribers": [
"FacebookAppDelegate"
]
}
}
35 changes: 35 additions & 0 deletions ios/ExpoAdapterFBSDKNext.podspec
@@ -0,0 +1,35 @@
require 'json'

package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))

Pod::Spec.new do |s|
s.name = 'ExpoAdapterFBSDKNext'
s.version = package['version']
s.summary = package['description']
s.description = package['description']
s.license = package['license']
s.author = package['author']
s.homepage = package['homepage']
s.platform = :ios, '12.0'
s.swift_version = '5.4'
s.source = { :git => 'https://github.com/thebergamo/react-native-fbsdk-next.git', :tag => "v#{package['version']}" }
s.static_framework = true

s.compiler_flags = %[-DRNBRANCH_VERSION=@\\"#{package["dependencies"]["react-native-fbsdk-next"]}\\"]

s.dependency 'ExpoModulesCore'
s.dependency 'React-Core'
s.dependency 'FBSDKCoreKit'

# Swift/Objective-C compatibility
s.pod_target_xcconfig = {
'DEFINES_MODULE' => 'YES'
}

if !$ExpoUseSources&.include?(package['name']) && ENV['EXPO_USE_SOURCE'].to_i == 0 && File.exist?("#{s.name}.xcframework") && Gem::Version.new(Pod::VERSION) >= Gem::Version.new('1.10.0')
s.source_files = "#{s.name}/**/*.h"
s.vendored_frameworks = "#{s.name}.xcframework"
else
s.source_files = "#{s.name}/**/*.{h,m,swift}"
end
end
21 changes: 21 additions & 0 deletions ios/ExpoAdapterFBSDKNext/FacebookAppDelegate.swift
@@ -0,0 +1,21 @@
import ExpoModulesCore
import FBSDKCoreKit

public class FacebookAppDelegate: ExpoAppDelegateSubscriber {
public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
ApplicationDelegate.shared.application(
application,
didFinishLaunchingWithOptions: launchOptions
)
return true
}

public func application(_ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
return ApplicationDelegate.shared.application(
application,
open: url,
sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String,
annotation: options[UIApplication.OpenURLOptionsKey.annotation]
)
}
}
1 change: 1 addition & 0 deletions jest.config.js
@@ -1,4 +1,5 @@
module.exports = {
preset: 'react-native',
setupFiles: ['./jest/setup.js'],
testPathIgnorePatterns: ['/node_modules/', '/lib/'],
};
17 changes: 14 additions & 3 deletions package.json
Expand Up @@ -48,8 +48,11 @@
],
"license": "MIT",
"scripts": {
"build:plugin": "tsc --build plugin",
"clean:plugin": "expo-module clean plugin",
"lint:plugin": "eslint plugin/src/*",
"start": "react-native start",
"prepare": "bob build",
"prepare": "bob build && npm run clean:plugin && npm run build:plugin",
"lint": "eslint ./src",
"test": "yarn validate:prettier && yarn validate:eslint && yarn jest",
"validate:eslint": "eslint \"src/**/*\"",
Expand All @@ -75,9 +78,15 @@
"README.md",
"react-native-fbsdk-next.podspec",
"jest",
"tsconfig.json"
"tsconfig.json",
"app.plugin.js",
"expo-module.config.json",
"plugin/build/"
],
"dependencies": {},
"dependencies": {
"@expo/config-plugins": "^4.0.4",
"xml2js": "^0.4.23"
},
"peerDependencies": {
"react-native": ">=0.63.3"
},
Expand All @@ -91,6 +100,7 @@
"@semantic-release/npm": "^9.0.0",
"@semantic-release/release-notes-generator": "^10.0.3",
"@trivago/prettier-plugin-sort-imports": "^3.2.0",
"@types/xml2js": "^0.4.9",
"@types/react": "^17.0.39",
"@types/react-native": "^0.66.16",
"@typescript-eslint/eslint-plugin": "^5.12.0",
Expand All @@ -99,6 +109,7 @@
"babel-plugin-module-resolver": "^4.0.0",
"conventional-changelog-conventionalcommits": "^4.6.3",
"eslint": "^8.9.0",
"expo-module-scripts": "^2.0.0",
"jest": "^27.5.1",
"metro-react-native-babel-preset": "^0.68.0",
"prettier": "^2.5.1",
Expand Down
43 changes: 43 additions & 0 deletions plugin/build/config.d.ts
@@ -0,0 +1,43 @@
import { ExpoConfig } from '@expo/config-types';
export declare type ExpoConfigFacebook = Pick<ExpoConfig, 'facebookScheme' | 'facebookAdvertiserIDCollectionEnabled' | 'facebookAppId' | 'facebookAutoInitEnabled' | 'facebookAutoLogAppEventsEnabled' | 'facebookDisplayName'>;
export declare type ConfigProps = {
/**
* Used for all Facebook libraries. Set up your Facebook App ID at https://developers.facebook.com.
*/
appID?: string;
/**
* Used for native Facebook login.
*/
displayName?: string;
/**
* Used for Facebook native login. Starts with 'fb' and followed by a string of digits, like 'fb1234567890'. You can find your scheme [here](https://developers.facebook.com/docs/facebook-login/ios)in the 'Configuring Your info.plist' section (only applicable to standalone apps and custom Expo Go apps).
*/
scheme?: string;
clientToken?: string;
/**
* Whether the Facebook SDK should be initialized automatically. The default in Expo (Client and in standalone apps) is `false`.
*/
isAutoInitEnabled?: boolean;
/**
* Whether the Facebook SDK log app events automatically. If you don't set this property, Facebook's default will be used. (Applicable only to standalone apps.) Note: The Facebook SDK must be initialized for app events to work. You may autoinitialize Facebook SDK by setting `isAutoInitEnabled` to `true`
*/
autoLogAppEventsEnabled?: boolean;
/**
* Whether the Facebook SDK should collect advertiser ID properties, like the Apple IDFA and Android Advertising ID, automatically. If you don't set this property, Facebook's default policy will be used. (Applicable only to standalone apps.)
*/
advertiserIDCollectionEnabled?: boolean;
/**
* Sets the iOS `NSUserTrackingUsageDescription` permission message in the `Info.plist`.
* Passing `false` will skip adding the permission.
* @default 'This identifier will be used to deliver personalized ads to you.'
*/
iosUserTrackingPermission?: string | false;
};
export declare function getMergePropsWithConfig(config: ExpoConfigFacebook, props: ConfigProps | void): ConfigProps;
export declare function getFacebookAppId(config: ConfigProps): string | null;
export declare function getFacebookClientToken(config: ConfigProps): string | null;
export declare function getFacebookScheme(config: ConfigProps): string | null;
export declare function getFacebookDisplayName(config: ConfigProps): string | null;
export declare function getFacebookAutoInitEnabled(config: ConfigProps): boolean | null;
export declare function getFacebookAutoLogAppEvents(config: ConfigProps): boolean | null;
export declare function getFacebookAdvertiserIDCollection(config: ConfigProps): boolean | null;
52 changes: 52 additions & 0 deletions plugin/build/config.js
@@ -0,0 +1,52 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getFacebookAdvertiserIDCollection = exports.getFacebookAutoLogAppEvents = exports.getFacebookAutoInitEnabled = exports.getFacebookDisplayName = exports.getFacebookScheme = exports.getFacebookClientToken = exports.getFacebookAppId = exports.getMergePropsWithConfig = void 0;
function getMergePropsWithConfig(config, props) {
const { facebookAppId, facebookDisplayName, facebookScheme, facebookAutoInitEnabled, facebookAutoLogAppEventsEnabled, facebookAdvertiserIDCollectionEnabled, } = config;
const { appID = facebookAppId, clientToken, displayName = facebookDisplayName, scheme = facebookScheme !== null && facebookScheme !== void 0 ? facebookScheme : (appID ? `fb${appID}` : undefined), isAutoInitEnabled = facebookAutoInitEnabled !== null && facebookAutoInitEnabled !== void 0 ? facebookAutoInitEnabled : false, autoLogAppEventsEnabled = facebookAutoLogAppEventsEnabled !== null && facebookAutoLogAppEventsEnabled !== void 0 ? facebookAutoLogAppEventsEnabled : false, advertiserIDCollectionEnabled = facebookAdvertiserIDCollectionEnabled !== null && facebookAdvertiserIDCollectionEnabled !== void 0 ? facebookAdvertiserIDCollectionEnabled : false, } = (props !== null && props !== void 0 ? props : {});
return {
appID,
clientToken,
displayName,
scheme,
isAutoInitEnabled,
autoLogAppEventsEnabled,
advertiserIDCollectionEnabled,
};
}
exports.getMergePropsWithConfig = getMergePropsWithConfig;
function getFacebookAppId(config) {
var _a;
return (_a = config.appID) !== null && _a !== void 0 ? _a : null;
}
exports.getFacebookAppId = getFacebookAppId;
function getFacebookClientToken(config) {
var _a;
return (_a = config.clientToken) !== null && _a !== void 0 ? _a : null;
}
exports.getFacebookClientToken = getFacebookClientToken;
function getFacebookScheme(config) {
var _a;
return (_a = config.scheme) !== null && _a !== void 0 ? _a : null;
}
exports.getFacebookScheme = getFacebookScheme;
function getFacebookDisplayName(config) {
var _a;
return (_a = config.displayName) !== null && _a !== void 0 ? _a : null;
}
exports.getFacebookDisplayName = getFacebookDisplayName;
function getFacebookAutoInitEnabled(config) {
var _a;
return (_a = config.isAutoInitEnabled) !== null && _a !== void 0 ? _a : null;
}
exports.getFacebookAutoInitEnabled = getFacebookAutoInitEnabled;
function getFacebookAutoLogAppEvents(config) {
var _a;
return (_a = config.autoLogAppEventsEnabled) !== null && _a !== void 0 ? _a : null;
}
exports.getFacebookAutoLogAppEvents = getFacebookAutoLogAppEvents;
function getFacebookAdvertiserIDCollection(config) {
var _a;
return (_a = config.advertiserIDCollectionEnabled) !== null && _a !== void 0 ? _a : null;
}
exports.getFacebookAdvertiserIDCollection = getFacebookAdvertiserIDCollection;
4 changes: 4 additions & 0 deletions plugin/build/withFacebook.d.ts
@@ -0,0 +1,4 @@
import { ConfigPlugin } from '@expo/config-plugins';
import { ConfigProps } from './config';
declare const _default: ConfigPlugin<void | ConfigProps>;
export default _default;
35 changes: 35 additions & 0 deletions plugin/build/withFacebook.js
@@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const config_plugins_1 = require("@expo/config-plugins");
const config_1 = require("./config");
const withFacebookAndroid_1 = require("./withFacebookAndroid");
const withFacebookIOS_1 = require("./withFacebookIOS");
const withSKAdNetworkIdentifiers_1 = require("./withSKAdNetworkIdentifiers");
// eslint-disable-next-line @typescript-eslint/no-var-requires
const pkg = require('react-native-fbsdk-next/package.json');
const withFacebook = (config, props) => {
const newProps = (0, config_1.getMergePropsWithConfig)(config, props);
if (!newProps.appID) {
throw new Error('missing appID in the plugin properties');
}
if (!newProps.displayName) {
throw new Error('missing displayName in the plugin properties');
}
if (!newProps.scheme) {
throw new Error('missing scheme in the plugin properties');
}
// Android
config = (0, withFacebookAndroid_1.withFacebookAppIdString)(config, newProps);
config = (0, withFacebookAndroid_1.withFacebookManifest)(config, newProps);
config = (0, withFacebookAndroid_1.withAndroidPermissions)(config, newProps);
// iOS
config = (0, withFacebookIOS_1.withFacebookIOS)(config, newProps);
config = (0, withFacebookIOS_1.withUserTrackingPermission)(config, newProps);
// https://developers.facebook.com/docs/SKAdNetwork
config = (0, withSKAdNetworkIdentifiers_1.withSKAdNetworkIdentifiers)(config, [
'v9wttpbfk9.skadnetwork',
'n38lu8286q.skadnetwork',
]);
return config;
};
exports.default = (0, config_plugins_1.createRunOncePlugin)(withFacebook, pkg.name, pkg.version);
6 changes: 6 additions & 0 deletions plugin/build/withFacebookAndroid.d.ts
@@ -0,0 +1,6 @@
import { AndroidConfig, ConfigPlugin } from '@expo/config-plugins';
import { ConfigProps } from './config';
export declare const withFacebookAppIdString: ConfigPlugin<ConfigProps>;
export declare const withFacebookManifest: ConfigPlugin<ConfigProps>;
export declare const withAndroidPermissions: ConfigPlugin<ConfigProps>;
export declare function setFacebookConfig(props: ConfigProps, androidManifest: AndroidConfig.Manifest.AndroidManifest): AndroidConfig.Manifest.AndroidManifest;

0 comments on commit d44e360

Please sign in to comment.