ios.tsx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. import ExternalLink from 'sentry/components/links/externalLink';
  2. import List from 'sentry/components/list/';
  3. import ListItem from 'sentry/components/list/listItem';
  4. import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
  5. import type {
  6. BasePlatformOptions,
  7. Docs,
  8. DocsParams,
  9. OnboardingConfig,
  10. } from 'sentry/components/onboarding/gettingStartedDoc/types';
  11. import {
  12. getReplayMobileConfigureDescription,
  13. getReplayVerifyStep,
  14. } from 'sentry/components/onboarding/gettingStartedDoc/utils/replayOnboarding';
  15. import {appleFeedbackOnboarding} from 'sentry/gettingStartedDocs/apple/macos';
  16. import {t, tct} from 'sentry/locale';
  17. import {getPackageVersion} from 'sentry/utils/gettingStartedDocs/getPackageVersion';
  18. import {getWizardInstallSnippet} from 'sentry/utils/gettingStartedDocs/mobileWizard';
  19. export enum InstallationMode {
  20. AUTO = 'auto',
  21. MANUAL = 'manual',
  22. }
  23. const platformOptions = {
  24. installationMode: {
  25. label: t('Installation Mode'),
  26. items: [
  27. {
  28. label: t('Auto'),
  29. value: InstallationMode.AUTO,
  30. },
  31. {
  32. label: t('Manual'),
  33. value: InstallationMode.MANUAL,
  34. },
  35. ],
  36. defaultValue:
  37. navigator.userAgent.indexOf('Win') === -1
  38. ? InstallationMode.AUTO
  39. : InstallationMode.MANUAL,
  40. },
  41. } satisfies BasePlatformOptions;
  42. type PlatformOptions = typeof platformOptions;
  43. type Params = DocsParams<PlatformOptions>;
  44. const isAutoInstall = (params: Params) =>
  45. params.platformOptions.installationMode === InstallationMode.AUTO;
  46. const getManualInstallSnippet = (params: Params) => `
  47. .package(url: "https://github.com/getsentry/sentry-cocoa", from: "${getPackageVersion(
  48. params,
  49. 'sentry.cocoa',
  50. '8.9.3'
  51. )}"),`;
  52. const getConfigurationSnippet = (params: Params) => `
  53. import Sentry
  54. // ....
  55. func application(_ application: UIApplication,
  56. didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
  57. SentrySDK.start { options in
  58. options.dsn = "${params.dsn.public}"
  59. options.debug = true // Enabling debug when first installing is always helpful
  60. // Adds IP for users.
  61. // For more information, visit: https://docs.sentry.io/platforms/apple/data-management/data-collected/
  62. options.sendDefaultPii = true${
  63. params.isPerformanceSelected
  64. ? `
  65. // Set tracesSampleRate to 1.0 to capture 100% of transactions for tracing.
  66. // We recommend adjusting this value in production.
  67. options.tracesSampleRate = 1.0`
  68. : ''
  69. }${
  70. params.isProfilingSelected &&
  71. params.profilingOptions?.defaultProfilingMode !== 'continuous'
  72. ? `
  73. // Sample rate for profiling, applied on top of TracesSampleRate.
  74. // We recommend adjusting this value in production.
  75. options.profilesSampleRate = 1.0`
  76. : ''
  77. }
  78. }${
  79. params.isProfilingSelected &&
  80. params.profilingOptions?.defaultProfilingMode === 'continuous'
  81. ? `
  82. // Manually call startProfiler and stopProfiler
  83. // to profile the code in between
  84. SentrySDK.startProfiler()
  85. // this code will be profiled
  86. //
  87. // Calls to stopProfiler are optional - if you don't stop the profiler, it will keep profiling
  88. // your application until the process exits or stopProfiler is called.
  89. SentrySDK.stopProfiler()`
  90. : ''
  91. }
  92. return true
  93. }`;
  94. const getConfigurationSnippetSwiftUi = (params: Params) => `
  95. import Sentry
  96. @main
  97. struct SwiftUIApp: App {
  98. init() {
  99. SentrySDK.start { options in
  100. options.dsn = "${params.dsn.public}"
  101. options.debug = true // Enabling debug when first installing is always helpful
  102. // Adds IP for users.
  103. // For more information, visit: https://docs.sentry.io/platforms/apple/data-management/data-collected/
  104. options.sendDefaultPii = true${
  105. params.isPerformanceSelected
  106. ? `
  107. // Set tracesSampleRate to 1.0 to capture 100% of transactions for tracing.
  108. // We recommend adjusting this value in production.
  109. options.tracesSampleRate = 1.0`
  110. : ''
  111. }${
  112. params.isProfilingSelected &&
  113. params.profilingOptions?.defaultProfilingMode !== 'continuous'
  114. ? `
  115. // Sample rate for profiling, applied on top of TracesSampleRate.
  116. // We recommend adjusting this value in production.
  117. options.profilesSampleRate = 1.0`
  118. : ''
  119. }
  120. }${
  121. params.isProfilingSelected &&
  122. params.profilingOptions?.defaultProfilingMode === 'continuous'
  123. ? `
  124. // Manually call startProfiler and stopProfiler
  125. // to profile the code in between
  126. SentrySDK.startProfiler()
  127. // this code will be profiled
  128. //
  129. // Calls to stopProfiler are optional - if you don't stop the profiler, it will keep profiling
  130. // your application until the process exits or stopProfiler is called.
  131. SentrySDK.stopProfiler()`
  132. : ''
  133. }
  134. }
  135. }`;
  136. const getVerifySnippet = () => `
  137. let button = UIButton(type: .roundedRect)
  138. button.frame = CGRect(x: 20, y: 50, width: 100, height: 30)
  139. button.setTitle("Break the world", for: [])
  140. button.addTarget(self, action: #selector(self.breakTheWorld(_:)), for: .touchUpInside)
  141. view.addSubview(button)
  142. @IBAction func breakTheWorld(_ sender: AnyObject) {
  143. fatalError("Break the world")
  144. }`;
  145. const getReplaySetupSnippet = (params: Params) => `
  146. SentrySDK.start(configureOptions: { options in
  147. options.dsn = "${params.dsn.public}"
  148. options.debug = true
  149. options.sessionReplay.onErrorSampleRate = 1.0
  150. options.sessionReplay.sessionSampleRate = 0.1
  151. })`;
  152. const getReplayConfigurationSnippet = () => `
  153. options.sessionReplay.redactAllText = true
  154. options.sessionReplay.redactAllImages = true`;
  155. const onboarding: OnboardingConfig<PlatformOptions> = {
  156. install: params =>
  157. isAutoInstall(params)
  158. ? [
  159. {
  160. type: StepType.INSTALL,
  161. description: (
  162. <p>
  163. {tct(
  164. 'Add Sentry automatically to your app with the [wizardLink:Sentry wizard] (call this inside your project directory).',
  165. {
  166. wizardLink: (
  167. <ExternalLink href="https://docs.sentry.io/platforms/apple/guides/ios/#install" />
  168. ),
  169. }
  170. )}
  171. </p>
  172. ),
  173. configurations: [
  174. {
  175. code: getWizardInstallSnippet({
  176. platform: 'ios',
  177. params,
  178. }),
  179. },
  180. ],
  181. },
  182. ]
  183. : [
  184. {
  185. type: StepType.INSTALL,
  186. description: tct(
  187. 'We recommend installing the SDK with Swift Package Manager (SPM), but we also support [alternateMethods: alternate installation methods]. To integrate Sentry into your Xcode project using SPM, open your App in Xcode and open [addPackage: File > Add Packages]. Then add the SDK by entering the Git repo url in the top right search field:',
  188. {
  189. alternateMethods: (
  190. <ExternalLink href="https://docs.sentry.io/platforms/apple/install/" />
  191. ),
  192. addPackage: <strong />,
  193. }
  194. ),
  195. configurations: [
  196. {
  197. language: 'url',
  198. code: `https://github.com/getsentry/sentry-cocoa.git`,
  199. },
  200. {
  201. description: (
  202. <p>
  203. {tct(
  204. 'Alternatively, when your project uses a [packageSwift: Package.swift] file to manage dependencies, you can specify the target with:',
  205. {
  206. packageSwift: <code />,
  207. }
  208. )}
  209. </p>
  210. ),
  211. language: 'swift',
  212. partialLoading: params.sourcePackageRegistries.isLoading,
  213. code: getManualInstallSnippet(params),
  214. },
  215. ],
  216. },
  217. ],
  218. configure: params =>
  219. isAutoInstall(params)
  220. ? [
  221. {
  222. type: StepType.CONFIGURE,
  223. description: (
  224. <p>{t('The Sentry wizard will automatically patch your application:')}</p>
  225. ),
  226. configurations: [
  227. {
  228. description: (
  229. <List symbol="bullet">
  230. <ListItem>
  231. {t('Install the Sentry SDK via Swift Package Manager or Cocoapods')}
  232. </ListItem>
  233. <ListItem>
  234. {tct(
  235. 'Update your [appDelegate: AppDelegate] or SwiftUI App Initializer with the default Sentry configuration and an example error',
  236. {
  237. appDelegate: <code />,
  238. }
  239. )}
  240. </ListItem>
  241. <ListItem>
  242. {tct(
  243. 'Add a new [code: Upload Debug Symbols] phase to your [code: xcodebuild] build script',
  244. {
  245. code: <code />,
  246. }
  247. )}
  248. </ListItem>
  249. <ListItem>
  250. {tct(
  251. 'Create [code: .sentryclirc] with an auth token to upload debug symbols (this file is automatically added to [code: .gitignore])',
  252. {
  253. code: <code />,
  254. }
  255. )}
  256. </ListItem>
  257. <ListItem>
  258. {t(
  259. "When you're using Fastlane, it will add a Sentry lane for uploading debug symbols"
  260. )}
  261. </ListItem>
  262. </List>
  263. ),
  264. },
  265. ],
  266. },
  267. ]
  268. : [
  269. {
  270. type: StepType.CONFIGURE,
  271. description: (
  272. <p>
  273. {tct(
  274. 'Make sure you initialize the SDK as soon as possible in your application lifecycle e.g. in your [appDelegate:] method:',
  275. {
  276. appDelegate: (
  277. <code>
  278. - [UIAppDelegate application:didFinishLaunchingWithOptions:]
  279. </code>
  280. ),
  281. }
  282. )}
  283. </p>
  284. ),
  285. configurations: [
  286. {
  287. language: 'swift',
  288. code: getConfigurationSnippet(params),
  289. },
  290. {
  291. description: (
  292. <p>
  293. {tct(
  294. "When using SwiftUI and your app doesn't implement an app delegate, initialize the SDK within the [initializer: App conformer's initializer]:",
  295. {
  296. initializer: (
  297. <ExternalLink href="https://developer.apple.com/documentation/swiftui/app/main()" />
  298. ),
  299. }
  300. )}
  301. </p>
  302. ),
  303. language: 'swift',
  304. code: getConfigurationSnippetSwiftUi(params),
  305. },
  306. ],
  307. },
  308. ],
  309. verify: params =>
  310. isAutoInstall(params)
  311. ? [
  312. {
  313. type: StepType.VERIFY,
  314. description: t(
  315. 'The Sentry wizard automatically adds a code snippet that captures a message to your project. Simply run your app and you should see this message in your Sentry project.'
  316. ),
  317. },
  318. ]
  319. : [
  320. {
  321. type: StepType.VERIFY,
  322. description: (
  323. <p>
  324. {tct(
  325. 'This snippet contains an intentional error you can use to test that errors are uploaded to Sentry correctly. You can add it to your main [viewController: ViewController].',
  326. {
  327. viewController: <code />,
  328. }
  329. )}
  330. </p>
  331. ),
  332. configurations: [
  333. {
  334. language: 'swift',
  335. code: getVerifySnippet(),
  336. },
  337. ],
  338. },
  339. ],
  340. nextSteps: () => [
  341. {
  342. id: 'cocoapods-carthage',
  343. name: t('CocoaPods/Carthage'),
  344. description: t(
  345. 'Learn about integrating Sentry into your project using CocoaPods or Carthage.'
  346. ),
  347. link: 'https://docs.sentry.io/platforms/apple/install/',
  348. },
  349. {
  350. id: 'debug-symbols',
  351. name: t('Debug Symbols'),
  352. description: t('Symbolicate and get readable stacktraces in your Sentry errors.'),
  353. link: 'https://docs.sentry.io/platforms/apple/dsym/',
  354. },
  355. {
  356. id: 'swiftui',
  357. name: t('SwiftUI'),
  358. description: t('Learn about our first class integration with SwiftUI.'),
  359. link: 'https://docs.sentry.io/platforms/apple/tracing/instrumentation/swiftui-instrumentation/',
  360. },
  361. ],
  362. };
  363. const replayOnboarding: OnboardingConfig<PlatformOptions> = {
  364. install: (params: Params) => [
  365. {
  366. type: StepType.INSTALL,
  367. description: t(
  368. 'Make sure your Sentry Cocoa SDK version is at least 8.43.0. If you already have the SDK installed, you can update it to the latest version with:'
  369. ),
  370. configurations: [
  371. {
  372. code: [
  373. {
  374. label: 'SPM',
  375. value: 'spm',
  376. language: 'swift',
  377. code: `.package(url: "https://github.com/getsentry/sentry-cocoa", from: "${getPackageVersion(
  378. params,
  379. 'sentry.cocoa',
  380. '8.36.0'
  381. )}"),`,
  382. },
  383. {
  384. label: 'CocoaPods',
  385. value: 'cocoapods',
  386. language: 'ruby',
  387. code: `pod update`,
  388. },
  389. {
  390. label: 'Carthage',
  391. value: 'carthage',
  392. language: 'swift',
  393. code: `github "getsentry/sentry-cocoa" "${getPackageVersion(
  394. params,
  395. 'sentry.cocoa',
  396. '8.36.0'
  397. )}"`,
  398. },
  399. ],
  400. },
  401. {
  402. description: t(
  403. 'To set up the integration, add the following to your Sentry initialization:'
  404. ),
  405. },
  406. {
  407. code: [
  408. {
  409. label: 'Swift',
  410. value: 'swift',
  411. language: 'swift',
  412. code: getReplaySetupSnippet(params),
  413. },
  414. ],
  415. },
  416. ],
  417. },
  418. ],
  419. configure: () => [
  420. {
  421. type: StepType.CONFIGURE,
  422. description: getReplayMobileConfigureDescription({
  423. link: 'https://docs.sentry.io/platforms/apple/guides/ios/session-replay/#privacy',
  424. }),
  425. configurations: [
  426. {
  427. description: t(
  428. 'The following code is the default configuration, which masks and blocks everything.'
  429. ),
  430. code: [
  431. {
  432. label: 'Swift',
  433. value: 'swift',
  434. language: 'swift',
  435. code: getReplayConfigurationSnippet(),
  436. },
  437. ],
  438. },
  439. ],
  440. },
  441. ],
  442. verify: getReplayVerifyStep({
  443. replayOnErrorSampleRateName: 'options\u200b.sessionReplay\u200b.onErrorSampleRate',
  444. replaySessionSampleRateName: 'options\u200b.sessionReplay\u200b.sessionSampleRate',
  445. }),
  446. nextSteps: () => [],
  447. };
  448. const docs: Docs<PlatformOptions> = {
  449. onboarding,
  450. feedbackOnboardingCrashApi: appleFeedbackOnboarding,
  451. crashReportOnboarding: appleFeedbackOnboarding,
  452. platformOptions,
  453. replayOnboarding,
  454. };
  455. export default docs;