|
import { join, relative } from "node:path" |
|
import { |
|
type ConfigPlugin, |
|
createRunOncePlugin, |
|
IOSConfig, |
|
withAppBuildGradle, |
|
withAppDelegate, |
|
withMainApplication, |
|
withXcodeProject, |
|
} from "@expo/config-plugins" |
|
import { addImports, findNewInstanceCodeBlock } from "@expo/config-plugins/build/android/codeMod" |
|
import { insertContentsInsideSwiftFunctionBlock } from "@expo/config-plugins/build/ios/codeMod" |
|
import { insertContentsAtOffset } from "@expo/config-plugins/build/utils/commonCodeMod" |
|
import { mergeContents } from "@expo/config-plugins/build/utils/generateCode" |
|
|
|
type DatadogConfig = { |
|
clientToken: string |
|
env: string |
|
applicationId: string |
|
nativeCrashReportEnabled: boolean |
|
nativeLongTaskThresholdMs?: number |
|
longTaskThresholdMs?: number |
|
sessionSamplingRate?: number |
|
site: "US1" | "US1_FED" | "US3" | "US5" | "EU1" | "AP1" |
|
trackingConsent?: "PENDING" | "GRANTED" | "NOT_GRANTED" |
|
telemetrySampleRate?: number |
|
vitalsUpdateFrequency?: "NEVER" | "RARE" | "AVERAGE" | "FREQUENT" |
|
uploadFrequency?: "RARE" | "AVERAGE" | "FREQUENT" |
|
batchSize?: "SMALL" | "MEDIUM" | "LARGE" |
|
trackFrustrations?: boolean |
|
trackBackgroundEvents?: boolean |
|
customEndpoints?: { |
|
rum?: string |
|
logs?: string |
|
trace?: string |
|
} |
|
nativeViewTracking?: boolean |
|
nativeInteractionTracking?: boolean |
|
verbosity?: "DEBUG" | "INFO" | "WARN" | "ERROR" |
|
proxy?: { |
|
type: "HTTP" | "HTTPS" | "SOCKS" |
|
address: string |
|
port: number |
|
username?: string |
|
password?: string |
|
} |
|
serviceName?: string |
|
version?: string |
|
firstPartyHosts?: Array<{ |
|
match: string |
|
propagatorTypes?: Array<"DATADOG" | "B3" | "B3MULTI" | "TRACECONTEXT"> |
|
}> |
|
trackInteractions: boolean |
|
trackResources: boolean |
|
trackErrors: boolean |
|
actionNameAttribute?: string |
|
useAccessibilityLabel?: boolean |
|
resourceTracingSamplingRate?: number |
|
bundleLogsWithRum?: boolean |
|
bundleLogsWithTraces?: boolean |
|
appHangThreshold?: number |
|
trackNonFatalAnrs?: boolean |
|
initialResourceThreshold?: number |
|
} |
|
|
|
/** |
|
* Adds Datadog native initialization to Android platform |
|
* This ensures Datadog SDK is initialized before React Native starts |
|
*/ |
|
const withAndroidDatadogInit: ConfigPlugin = (config) => { |
|
return withMainApplication(config, async (config) => { |
|
// Add the import for Datadog native initialization |
|
config.modResults.contents = addImports( |
|
config.modResults.contents, |
|
["com.datadog.reactnative.DdSdkNativeInitialization"], |
|
false, |
|
) |
|
|
|
// Add the initialization call in onCreate() after super.onCreate() |
|
const initCall = "DdSdkNativeInitialization.initFromNative(this.applicationContext)\n" |
|
const res = findNewInstanceCodeBlock(config.modResults.contents, "onCreate", "kt") |
|
|
|
if (!config.modResults.contents.includes(initCall) && res) { |
|
const superOnCreateCall = "super.onCreate()" |
|
const index = res.code.indexOf(superOnCreateCall) |
|
|
|
if (index !== -1) { |
|
config.modResults.contents = insertContentsAtOffset( |
|
config.modResults.contents, |
|
initCall, |
|
res.start + index + superOnCreateCall.length + 1, |
|
) |
|
} |
|
} |
|
|
|
return config |
|
}) |
|
} |
|
|
|
/** |
|
* Adds Datadog native initialization to iOS platform |
|
* This ensures Datadog SDK is initialized before React Native starts |
|
*/ |
|
const withIOSDatadogInit: ConfigPlugin = (config) => { |
|
return withAppDelegate(config, (config) => { |
|
let contents = config.modResults.contents |
|
|
|
// Add the import for DatadogSDKReactNative |
|
contents = mergeContents({ |
|
anchor: /import Expo/, |
|
comment: "//", |
|
newSrc: "import DatadogSDKReactNative", |
|
offset: 1, |
|
src: contents, |
|
tag: "ios-datadog-import", |
|
}).contents |
|
|
|
// Add the initialization call at the beginning of didFinishLaunchingWithOptions |
|
contents = insertContentsInsideSwiftFunctionBlock( |
|
contents, |
|
"application(_:didFinishLaunchingWithOptions:)", |
|
"DdSdk.initFromNative()", |
|
{ position: "head" }, |
|
) |
|
|
|
config.modResults.contents = contents |
|
return config |
|
}) |
|
} |
|
|
|
/** |
|
* Configures Android gradle to include Datadog configuration |
|
*/ |
|
const withAndroidDatadogGradle: ConfigPlugin = (config) => { |
|
return withAppBuildGradle(config, (config) => { |
|
let contents = config.modResults.contents |
|
|
|
// Add the datadog configuration gradle script |
|
contents = mergeContents({ |
|
anchor: /apply plugin: "com\.facebook\.react"/, |
|
comment: "//", |
|
newSrc: `apply from: "${config.modRequest.projectRoot}/node_modules/@datadog/mobile-react-native/datadog-configuration.gradle"`, |
|
offset: 1, |
|
src: contents, |
|
tag: "datadog-configuration-gradle", |
|
}).contents |
|
|
|
config.modResults.contents = contents |
|
return config |
|
}) |
|
} |
|
|
|
/** |
|
* Configures iOS to include the Datadog configuration file as a resource |
|
*/ |
|
const withIOSDatadogConfig: ConfigPlugin = (config) => { |
|
return withXcodeProject(config, (config) => { |
|
const projectRoot = config.modRequest.projectRoot |
|
const configFileName = "datadog-configuration.json" |
|
const configFilePath = join(projectRoot, configFileName) |
|
|
|
// Add the configuration file as a resource to the iOS project |
|
try { |
|
const relativePath = relative(config.modRequest.platformProjectRoot, configFilePath) |
|
IOSConfig.XcodeUtils.addResourceFileToGroup({ |
|
filepath: relativePath, |
|
groupName: "Resources", |
|
isBuildFile: true, |
|
project: config.modResults, |
|
targetUuid: config.modResults.getFirstTarget().uuid, |
|
verbose: true, |
|
}) |
|
} catch (error) { |
|
console.warn("Warning: Could not add datadog-configuration.json to iOS resources:", error) |
|
} |
|
|
|
return config |
|
}) |
|
} |
|
|
|
/** |
|
* Main plugin that combines all Datadog native initialization features |
|
*/ |
|
const withDatadogNativeInit: ConfigPlugin<DatadogConfig> = (c) => { |
|
let config = c |
|
|
|
// Configure Android |
|
config = withAndroidDatadogGradle(config) |
|
config = withAndroidDatadogInit(config) |
|
|
|
// Configure iOS |
|
config = withIOSDatadogConfig(config) |
|
config = withIOSDatadogInit(config) |
|
|
|
return config |
|
} |
|
|
|
export default createRunOncePlugin(withDatadogNativeInit, "DatadogNativeInitialization", "2.0.0") |