ios.tsx 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  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.MANUAL
  39. : InstallationMode.AUTO,
  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. params.isPerformanceSelected
  61. ? `
  62. // Set tracesSampleRate to 1.0 to capture 100% of transactions for tracing.
  63. // We recommend adjusting this value in production.
  64. options.tracesSampleRate = 1.0`
  65. : ''
  66. }${
  67. params.isProfilingSelected &&
  68. params.profilingOptions?.defaultProfilingMode !== 'continuous'
  69. ? `
  70. // Sample rate for profiling, applied on top of TracesSampleRate.
  71. // We recommend adjusting this value in production.
  72. options.profilesSampleRate = 1.0`
  73. : ''
  74. }
  75. }${
  76. params.isProfilingSelected &&
  77. params.profilingOptions?.defaultProfilingMode === 'continuous'
  78. ? `
  79. // Manually call startProfiler and stopProfiler
  80. // to profile the code in between
  81. SentrySDK.startProfiler()
  82. // this code will be profiled
  83. //
  84. // Calls to stopProfiler are optional - if you don't stop the profiler, it will keep profiling
  85. // your application until the process exits or stopProfiler is called.
  86. SentrySDK.stopProfiler()`
  87. : ''
  88. }
  89. return true
  90. }`;
  91. const getConfigurationSnippetSwiftUi = (params: Params) => `
  92. import Sentry
  93. @main
  94. struct SwiftUIApp: App {
  95. init() {
  96. SentrySDK.start { options in
  97. options.dsn = "${params.dsn.public}"
  98. options.debug = true // Enabling debug when first installing is always helpful${
  99. params.isPerformanceSelected
  100. ? `
  101. // Set tracesSampleRate to 1.0 to capture 100% of transactions for tracing.
  102. // We recommend adjusting this value in production.
  103. options.tracesSampleRate = 1.0`
  104. : ''
  105. }${
  106. params.isProfilingSelected &&
  107. params.profilingOptions?.defaultProfilingMode !== 'continuous'
  108. ? `
  109. // Sample rate for profiling, applied on top of TracesSampleRate.
  110. // We recommend adjusting this value in production.
  111. options.profilesSampleRate = 1.0`
  112. : ''
  113. }
  114. }${
  115. params.isProfilingSelected &&
  116. params.profilingOptions?.defaultProfilingMode === 'continuous'
  117. ? `
  118. // Manually call startProfiler and stopProfiler
  119. // to profile the code in between
  120. SentrySDK.startProfiler()
  121. // this code will be profiled
  122. //
  123. // Calls to stopProfiler are optional - if you don't stop the profiler, it will keep profiling
  124. // your application until the process exits or stopProfiler is called.
  125. SentrySDK.stopProfiler()`
  126. : ''
  127. }
  128. }
  129. }`;
  130. const getVerifySnippet = () => `
  131. let button = UIButton(type: .roundedRect)
  132. button.frame = CGRect(x: 20, y: 50, width: 100, height: 30)
  133. button.setTitle("Break the world", for: [])
  134. button.addTarget(self, action: #selector(self.breakTheWorld(_:)), for: .touchUpInside)
  135. view.addSubview(button)
  136. @IBAction func breakTheWorld(_ sender: AnyObject) {
  137. fatalError("Break the world")
  138. }`;
  139. const getExperimentalFeaturesSnippetSwift = () => `
  140. import Sentry
  141. SentrySDK.start { options in
  142. // ...
  143. // Enable all experimental features
  144. options.attachViewHierarchy = true
  145. options.enableMetricKit = true
  146. options.enableTimeToFullDisplayTracing = true
  147. options.swiftAsyncStacktraces = true
  148. options.enableAppLaunchProfiling = true
  149. }`;
  150. const getExperimentalFeaturesSnippetObjC = () => `
  151. @import Sentry;
  152. [SentrySDK startWithConfigureOptions:^(SentryOptions *options) {
  153. // ...
  154. // Enable all experimental features
  155. options.attachViewHierarchy = YES;
  156. options.enableMetricKit = YES;
  157. options.enableTimeToFullDisplayTracing = YES;
  158. options.swiftAsyncStacktraces = YES;
  159. options.enableAppLaunchProfiling = YES;
  160. }];`;
  161. const getReplaySetupSnippet = (params: Params) => `
  162. SentrySDK.start(configureOptions: { options in
  163. options.dsn = "${params.dsn.public}"
  164. options.debug = true
  165. options.sessionReplay.onErrorSampleRate = 1.0
  166. options.sessionReplay.sessionSampleRate = 0.1
  167. })`;
  168. const getReplayConfigurationSnippet = () => `
  169. options.sessionReplay.redactAllText = true
  170. options.sessionReplay.redactAllImages = true`;
  171. const onboarding: OnboardingConfig<PlatformOptions> = {
  172. install: params =>
  173. isAutoInstall(params)
  174. ? [
  175. {
  176. type: StepType.INSTALL,
  177. description: (
  178. <p>
  179. {tct(
  180. 'Add Sentry automatically to your app with the [wizardLink:Sentry wizard] (call this inside your project directory).',
  181. {
  182. wizardLink: (
  183. <ExternalLink href="https://docs.sentry.io/platforms/apple/guides/ios/#install" />
  184. ),
  185. }
  186. )}
  187. </p>
  188. ),
  189. configurations: [
  190. {
  191. code: getWizardInstallSnippet({
  192. platform: 'ios',
  193. params,
  194. }),
  195. },
  196. ],
  197. },
  198. ]
  199. : [
  200. {
  201. type: StepType.INSTALL,
  202. description: tct(
  203. '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:',
  204. {
  205. alternateMethods: (
  206. <ExternalLink href="https://docs.sentry.io/platforms/apple/install/" />
  207. ),
  208. addPackage: <strong />,
  209. }
  210. ),
  211. configurations: [
  212. {
  213. language: 'url',
  214. code: `https://github.com/getsentry/sentry-cocoa.git`,
  215. },
  216. {
  217. description: (
  218. <p>
  219. {tct(
  220. 'Alternatively, when your project uses a [packageSwift: Package.swift] file to manage dependencies, you can specify the target with:',
  221. {
  222. packageSwift: <code />,
  223. }
  224. )}
  225. </p>
  226. ),
  227. language: 'swift',
  228. partialLoading: params.sourcePackageRegistries.isLoading,
  229. code: getManualInstallSnippet(params),
  230. },
  231. ],
  232. },
  233. ],
  234. configure: params =>
  235. isAutoInstall(params)
  236. ? [
  237. {
  238. type: StepType.CONFIGURE,
  239. description: (
  240. <p>{t('The Sentry wizard will automatically patch your application:')}</p>
  241. ),
  242. configurations: [
  243. {
  244. description: (
  245. <List symbol="bullet">
  246. <ListItem>
  247. {t('Install the Sentry SDK via Swift Package Manager or Cocoapods')}
  248. </ListItem>
  249. <ListItem>
  250. {tct(
  251. 'Update your [appDelegate: AppDelegate] or SwiftUI App Initializer with the default Sentry configuration and an example error',
  252. {
  253. appDelegate: <code />,
  254. }
  255. )}
  256. </ListItem>
  257. <ListItem>
  258. {tct(
  259. 'Add a new [code: Upload Debug Symbols] phase to your [code: xcodebuild] build script',
  260. {
  261. code: <code />,
  262. }
  263. )}
  264. </ListItem>
  265. <ListItem>
  266. {tct(
  267. 'Create [code: .sentryclirc] with an auth token to upload debug symbols (this file is automatically added to [code: .gitignore])',
  268. {
  269. code: <code />,
  270. }
  271. )}
  272. </ListItem>
  273. <ListItem>
  274. {t(
  275. "When you're using Fastlane, it will add a Sentry lane for uploading debug symbols"
  276. )}
  277. </ListItem>
  278. </List>
  279. ),
  280. },
  281. ],
  282. },
  283. ]
  284. : [
  285. {
  286. type: StepType.CONFIGURE,
  287. description: (
  288. <p>
  289. {tct(
  290. 'Make sure you initialize the SDK as soon as possible in your application lifecycle e.g. in your [appDelegate:] method:',
  291. {
  292. appDelegate: (
  293. <code>
  294. - [UIAppDelegate application:didFinishLaunchingWithOptions:]
  295. </code>
  296. ),
  297. }
  298. )}
  299. </p>
  300. ),
  301. configurations: [
  302. {
  303. language: 'swift',
  304. code: getConfigurationSnippet(params),
  305. },
  306. {
  307. description: (
  308. <p>
  309. {tct(
  310. "When using SwiftUI and your app doesn't implement an app delegate, initialize the SDK within the [initializer: App conformer's initializer]:",
  311. {
  312. initializer: (
  313. <ExternalLink href="https://developer.apple.com/documentation/swiftui/app/main()" />
  314. ),
  315. }
  316. )}
  317. </p>
  318. ),
  319. language: 'swift',
  320. code: getConfigurationSnippetSwiftUi(params),
  321. },
  322. ],
  323. },
  324. ],
  325. verify: params =>
  326. isAutoInstall(params)
  327. ? [
  328. {
  329. type: StepType.VERIFY,
  330. description: t(
  331. '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.'
  332. ),
  333. },
  334. {
  335. title: t('Experimental Features'),
  336. description: tct(
  337. 'Want to play with some new features? Try out our experimental features for [vh: View Hierarchy], [ttfd: Time to Full Display (TTFD)], [metricKit: MetricKit], [prewarmedAppStart: Prewarmed App Start Tracing], and [asyncStacktraces: Swift Async Stacktraces]. Experimental features are still a work-in-progress and may have bugs. We recognize the irony. [break] Let us know if you have feedback through [gh: GitHub issues].',
  338. {
  339. vh: (
  340. <ExternalLink href="https://docs.sentry.io/platforms/apple/guides/ios/enriching-events/viewhierarchy/" />
  341. ),
  342. ttfd: (
  343. <ExternalLink href="https://docs.sentry.io/platforms/apple/guides/ios/tracing/instrumentation/automatic-instrumentation/#time-to-full-display" />
  344. ),
  345. metricKit: (
  346. <ExternalLink href="https://docs.sentry.io/platforms/apple/guides/watchos/configuration/metric-kit/" />
  347. ),
  348. prewarmedAppStart: (
  349. <ExternalLink href="https://docs.sentry.io/platforms/apple/tracing/instrumentation/automatic-instrumentation/#prewarmed-app-start-tracing" />
  350. ),
  351. asyncStacktraces: (
  352. <ExternalLink href="https://docs.sentry.io/platforms/apple/guides/ios/#stitch-together-swift-concurrency-stack-traces" />
  353. ),
  354. gh: (
  355. <ExternalLink href="https://github.com/getsentry/sentry-cocoa/issues" />
  356. ),
  357. break: <br />,
  358. }
  359. ),
  360. configurations: [
  361. {
  362. code: [
  363. {
  364. label: 'Swift',
  365. value: 'swift',
  366. language: 'swift',
  367. code: getExperimentalFeaturesSnippetSwift(),
  368. },
  369. {
  370. label: 'Objective-C',
  371. value: 'c',
  372. language: 'c',
  373. code: getExperimentalFeaturesSnippetObjC(),
  374. },
  375. ],
  376. },
  377. ],
  378. },
  379. ]
  380. : [
  381. {
  382. type: StepType.VERIFY,
  383. description: (
  384. <p>
  385. {tct(
  386. '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].',
  387. {
  388. viewController: <code />,
  389. }
  390. )}
  391. </p>
  392. ),
  393. configurations: [
  394. {
  395. language: 'swift',
  396. code: getVerifySnippet(),
  397. },
  398. ],
  399. },
  400. ],
  401. nextSteps: () => [
  402. {
  403. id: 'cocoapods-carthage',
  404. name: t('CocoaPods/Carthage'),
  405. description: t(
  406. 'Learn about integrating Sentry into your project using CocoaPods or Carthage.'
  407. ),
  408. link: 'https://docs.sentry.io/platforms/apple/install/',
  409. },
  410. {
  411. id: 'debug-symbols',
  412. name: t('Debug Symbols'),
  413. description: t('Symbolicate and get readable stacktraces in your Sentry errors.'),
  414. link: 'https://docs.sentry.io/platforms/apple/dsym/',
  415. },
  416. {
  417. id: 'swiftui',
  418. name: t('SwiftUI'),
  419. description: t('Learn about our first class integration with SwiftUI.'),
  420. link: 'https://docs.sentry.io/platforms/apple/tracing/instrumentation/swiftui-instrumentation/',
  421. },
  422. ],
  423. };
  424. const replayOnboarding: OnboardingConfig<PlatformOptions> = {
  425. install: (params: Params) => [
  426. {
  427. type: StepType.INSTALL,
  428. description: t(
  429. '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:'
  430. ),
  431. configurations: [
  432. {
  433. code: [
  434. {
  435. label: 'SPM',
  436. value: 'spm',
  437. language: 'swift',
  438. code: `.package(url: "https://github.com/getsentry/sentry-cocoa", from: "${getPackageVersion(
  439. params,
  440. 'sentry.cocoa',
  441. '8.36.0'
  442. )}"),`,
  443. },
  444. {
  445. label: 'CocoaPods',
  446. value: 'cocoapods',
  447. language: 'ruby',
  448. code: `pod update`,
  449. },
  450. {
  451. label: 'Carthage',
  452. value: 'carthage',
  453. language: 'swift',
  454. code: `github "getsentry/sentry-cocoa" "${getPackageVersion(
  455. params,
  456. 'sentry.cocoa',
  457. '8.36.0'
  458. )}"`,
  459. },
  460. ],
  461. },
  462. {
  463. description: t(
  464. 'To set up the integration, add the following to your Sentry initialization:'
  465. ),
  466. },
  467. {
  468. code: [
  469. {
  470. label: 'Swift',
  471. value: 'swift',
  472. language: 'swift',
  473. code: getReplaySetupSnippet(params),
  474. },
  475. ],
  476. },
  477. ],
  478. },
  479. ],
  480. configure: () => [
  481. {
  482. type: StepType.CONFIGURE,
  483. description: getReplayMobileConfigureDescription({
  484. link: 'https://docs.sentry.io/platforms/apple/guides/ios/session-replay/#privacy',
  485. }),
  486. configurations: [
  487. {
  488. description: t(
  489. 'The following code is the default configuration, which masks and blocks everything.'
  490. ),
  491. code: [
  492. {
  493. label: 'Swift',
  494. value: 'swift',
  495. language: 'swift',
  496. code: getReplayConfigurationSnippet(),
  497. },
  498. ],
  499. },
  500. ],
  501. },
  502. ],
  503. verify: getReplayVerifyStep({
  504. replayOnErrorSampleRateName: 'options\u200b.sessionReplay\u200b.onErrorSampleRate',
  505. replaySessionSampleRateName: 'options\u200b.sessionReplay\u200b.sessionSampleRate',
  506. }),
  507. nextSteps: () => [],
  508. };
  509. const docs: Docs<PlatformOptions> = {
  510. onboarding,
  511. feedbackOnboardingCrashApi: appleFeedbackOnboarding,
  512. crashReportOnboarding: appleFeedbackOnboarding,
  513. platformOptions,
  514. replayOnboarding,
  515. };
  516. export default docs;