{"id":4639,"date":"2023-01-12T11:55:24","date_gmt":"2023-01-12T16:55:24","guid":{"rendered":"https:\/\/ionic.io\/blog\/?p=4639"},"modified":"2023-01-12T11:55:44","modified_gmt":"2023-01-12T16:55:44","slug":"introducing-trapeze","status":"publish","type":"post","link":"https:\/\/ionic.io\/blog\/introducing-trapeze","title":{"rendered":"Introducing Trapeze: Easy iOS and Android Project Configuration"},"content":{"rendered":"\n<div class=\"wp-block-jetpack-markdown\"><p>Today I\u2019m excited to announce the public availability of <a href=\"https:\/\/trapeze.dev\">Trapeze<\/a>, our new open-source project that makes it easy to manage native and cross-platform mobile projects from a simple YAML-based configuration-file format.<\/p>\n<p>Through this configuration file, Trapeze can work with the common file formats found in native iOS and Android projects, such as Gradle, XML, JSON, XCConfig, Strings, PBXProj, PList, Android Resources, and others. Trapeze supports traditional iOS and Android apps, and cross-platform frameworks like Ionic, Capacitor, React Native, and Flutter.<\/p>\n<p>Trapeze was built to solve key challenges the mobile community faces when managing mobile projects at scale, especially in Mobile CI\/CD workflows. Read on to learn more about Trapeze and where we\u2019re taking it.<\/p>\n<h2>Solving Mobile Project Automation<\/h2>\n<p>As apps become more complex, teams need to manage their project configuration in safer, more automated ways. For example, keeping an auto-incrementing build number, or applying a set of project changes for a while-labeled app. These tasks are slow and error-prone to do by hand, and the current best alternative is to write custom configuration scripts that are hard to build and even harder to maintain.<\/p>\n<p>With Trapeze, these tasks are as simple as defining the changes in a YAML file and running the Trapeze Configure tool. For example, the <code>incrementBuild<\/code> operation increments the build number each time the tool is run:<\/p>\n<pre><code class=\"language-yaml\">platforms:\n  ios:\n\tincrementBuild: true\n<\/code><\/pre>\n<pre><code>npx trapeze run config.yml\n<\/code><\/pre>\n<p>Trapeze comes with a <a href=\"https:\/\/trapeze.dev\/docs\/Operations\/getting-started\">large set of supported operations<\/a> across <a href=\"https:\/\/trapeze.dev\/docs\/Operations\/ios\">iOS<\/a> and <a href=\"https:\/\/trapeze.dev\/docs\/Operations\/android\">Android<\/a>, as well as some other useful operations that can work across projects.<\/p>\n<h2>Common Tasks<\/h2>\n<p>Some examples of tasks that Trapeze is well suited for:<\/p>\n<h3>Build Settings<\/h3>\n<p>Adjusting build settings and basic app configuration can be done in a central place:<\/p>\n<pre><code class=\"language-yaml\">vars:\n  BUNDLE_ID:\n\tdefault: io.ionic.app\n  PACKAGE_NAME:\n\tdefault: io.ionic.app\n\nplatforms:\n  ios:\n\ttargets:\n  \tApp:\n    \tbundleId: $BUNDLE_ID\n    \tversion: 16.4\n    \tbuildNumber: 198\n    \tproductName: Awesome App\n    \tdisplayName: My Awesome App\n\n  android:\n\tpackageName: $PACKAGE_NAME\n\tversionName: 5.2.1\n\tversionCode: 197\n<\/code><\/pre>\n<h3>Build-specific Configuration Files<\/h3>\n<p>Apps often have to provide different configuration files and values when building for different environments (dev\/qa\/prod\/etc). For example, swapping out values in a <code>google-services.json<\/code> file depending on the environment:<\/p>\n<pre><code class=\"language-yaml\">vars:\n  GOOGLE_PROJECT_ID:\n\tdefault: &quot;default_id&quot;\n\nplatforms:\n  android:\n\tjson:\n  \t- file: google-services.json\n    \tset:\n      \tproject_info:\n        \tproject_id: $GOOGLE_PROJECT_ID\n  ios:\n\ttargets:\n  \tApp:\n    \tjson:\n      \t- file: google-services.json\n        \tset:\n          \tproject_info:\n            \tproject_id: $GOOGLE_PROJECT_ID\n<\/code><\/pre>\n<h3>i18n and l10n<\/h3>\n<p>Swapping out translations and other localized values can be done by modifying the relevant platform-specific files (such as .strings on iOS and XML resource files on Android):<\/p>\n<pre><code class=\"language-yaml\">platforms:\n  ios:\n\ttargets:\n  \tApp:\n    \tstrings:\n      \t- file: App\/Lang\/fr.strings\n        \tset:\n          \t&quot;App name&quot;: Name\n  android:\n\t- resFile: values-fr\/strings.xml\n  \ttarget: resources\/string[@name=&quot;app_name&quot;]\n  \treplace: |\n    \t&lt;string name=&quot;app_name&quot;&gt;Name&lt;\/string&gt;\n<\/code><\/pre>\n<p>This is just a taste of the use-cases for Trapeze!<\/p>\n<h2>Support for Environment Variables<\/h2>\n<p>Trapeze can work with Environment variables, including complex JSON-valued ones. When running interactively, Trapeze can prompt the user to provide values for all specified variables, if they aren\u2019t already defined in the environment. For JSON values, Trapeze supports substituting in portions of the YAML configuration for complex variable substitution.<\/p>\n<pre><code class=\"language-yaml\">vars:\n\tKEYCHAIN_GROUPS:\n  \tdefault:\n    \t[\n      \t&#039;$BUNDLE_ID&#039;,\n    \t]\n\nplatforms:\n  ios:\n\ttargets:\n  \tApp:\n    \tentitlements:\n      \t- keychain-access-groups: $KEYCHAIN_GROUPS\n<\/code><\/pre>\n<h2>CI\/CD Ready<\/h2>\n<p>As more teams start to adopt a Mobile CI\/CD workflow, such as those using our <a href=\"https:\/\/useappflow.com\">Appflow Mobile CI\/CD service<\/a>, we\u2019ve seen a rise in questions around automating project configuration in these systems.<\/p>\n<p>Trapeze was built with CI\/CD in mind, and is a perfect fit for Appflow. For example, here is how developers would run a Trapeze configuration step in their build pipeline, before the app is packaged by Appflow:<\/p>\n<pre><code class=\"language-json\">  &quot;scripts&quot;: {\n\t&quot;appflow:build&quot;: &quot;npx trapeze run appflow.yml -y &amp;&amp; npm run build&quot;\n  },\n<\/code><\/pre>\n<h2>For Plugin Authors<\/h2>\n<p>Another key audience we have in mind for Trapeze are plugin authors. Often, plugins require some manual project configuration in order to install. This can be difficult for users of these plugins and result in incorrectly configured apps and increased support burden.<\/p>\n<p>To fix this, plugin authors can ship a Trapeze YAML file and then apply it after plugin install. Combined with interactive environment variable support, users of the plugin can be prompted to customize the values their project will be configured with.<\/p>\n<p>Let&#8217;s look at two real plugin examples to see how this might be used.<\/p>\n<p>The first one is the <a href=\"https:\/\/capacitorjs.com\/docs\/apis\/camera\">Capacitor Camera plugin<\/a>. On iOS and Android some additional permission configuration needs to be set by the developer before the plugin can be used. We could supply a Trapeze configuration file to prompt the user for these values and modify the project for them automatically:<\/p>\n<pre><code>platforms:\n  ios:\n    targets:\n      App:\n        plist:\n          - entries:\n              - NSCameraUsageDescription: &quot;Take photos&quot;\n              - NSPhotoLibraryAddUsageDescription: &quot;Add  photos&quot;\n              - NSPhotoLibraryUsageDescription: &quot;Access photos&quot;\n  android:\n    manifest:\n      - file: AndroidManifest.xml\n        target: manifest\/application\n        inject:\n          &lt;uses-permission android:name=&quot;android.permission.READ_EXTERNAL_STORAGE&quot;\/&gt;\n          &lt;uses-permission android:name=&quot;android.permission.WRITE_EXTERNAL_STORAGE&quot; \/&gt;\n<\/code><\/pre>\n<p>On another one of Ionic\u2019s plugins, a set of build options and Android manifest changes need to be applied after the plugin is installed.<\/p>\n<pre><code class=\"language-yaml\">platforms:\n  ios:\n\ttargets:\n  \tApp:\n    \tbuildSettings:\n      \tENABLE_BITCODE: false\n      \tSTRIP_SWIFT_SYMBOLS: false\n\n    \tplist:\n      \treplace: false\n      \tentries:\n        \t- CFBundleURLTypes:\n            \t- CFBundleURLSchemes:\n                \t- msauth.$(PRODUCT_BUNDLE_IDENTIFIER)\n                \t- msauth.$(PRODUCT_BUNDLE_IDENTIFIER)-intunemam\n                \t- msauth.com.microsoft.intunemam\n  android:\n\tmanifest:\n  \t- file: AndroidManifest.xml\n    \ttarget: manifest\n    \tinject: |\n      \t&lt;queries&gt;\n        \t&lt;!-- ... --&gt;\n      \t&lt;\/queries&gt;\n<\/code><\/pre>\n<p>Both of these file can be run by the user after installing the plugin or automatically using postinstall hooks.<\/p>\n<h2>What\u2019s Next?<\/h2>\n<p>The goal for Trapeze is to support all of the file formats and project automation tasks that mobile developers need. <a href=\"https:\/\/npmcharts.com\/compare\/@trapezedev\/project?interval=30\">Early growth<\/a> is exciting and we are frequently adding new features based on feedback.<\/p>\n<p>To give Trapeze a try, visit <a href=\"https:\/\/trapeze.dev\">trapeze.dev<\/a> and install the tool to start running project modification tasks. The project is 100% free and open source and we\u2019d love your feedback on the <a href=\"https:\/\/github.com\/ionic-team\/trapeze\">GitHub repo<\/a>.<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Meet Trapeze, our new open-source project that lets you manage native and cross-platform mobile projects from a simple YAML-based configuration-file format.<\/p>\n","protected":false},"author":3,"featured_media":4625,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"publish_to_discourse":"","publish_post_category":"","wpdc_auto_publish_overridden":"","wpdc_topic_tags":"","wpdc_pin_topic":"","wpdc_pin_until":"","discourse_post_id":"","discourse_permalink":"","wpdc_publishing_response":"","wpdc_publishing_error":"","_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1,120,122],"tags":[267],"class_list":["post-4639","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-all","category-announcements","category-product","tag-trapeze"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v23.0 (Yoast SEO v23.0) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Introducing Trapeze: Easy iOS and Android Project Configuration<\/title>\n<meta name=\"description\" content=\"Trapeze is an open-source project that lets you manage native &amp; cross-platform mobile projects from a YAML-based configuration-file format.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/ionic.io\/blog\/introducing-trapeze\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Introducing Trapeze: Easy iOS and Android Project Configuration\" \/>\n<meta property=\"og:description\" content=\"Trapeze is an open-source project that lets you manage native &amp; cross-platform mobile projects from a YAML-based configuration-file format.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/ionic.io\/blog\/introducing-trapeze\" \/>\n<meta property=\"og:site_name\" content=\"Ionic Blog\" \/>\n<meta property=\"article:published_time\" content=\"2023-01-12T16:55:24+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-01-12T16:55:44+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/01\/trapeze-ionic-feature-image.png\" \/>\n\t<meta property=\"og:image:width\" content=\"2240\" \/>\n\t<meta property=\"og:image:height\" content=\"1120\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Max Lynch\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@maxlynch\" \/>\n<meta name=\"twitter:site\" content=\"@ionicframework\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Max Lynch\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/ionic.io\/blog\/introducing-trapeze#article\",\"isPartOf\":{\"@id\":\"https:\/\/ionic.io\/blog\/introducing-trapeze\"},\"author\":{\"name\":\"Max Lynch\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/91f360cffbd804a464b0c4a87b5c5f1e\"},\"headline\":\"Introducing Trapeze: Easy iOS and Android Project Configuration\",\"datePublished\":\"2023-01-12T16:55:24+00:00\",\"dateModified\":\"2023-01-12T16:55:44+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/ionic.io\/blog\/introducing-trapeze\"},\"wordCount\":756,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/ionic.io\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/introducing-trapeze#primaryimage\"},\"thumbnailUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/01\/trapeze-ionic-feature-image.png\",\"keywords\":[\"trapeze\"],\"articleSection\":[\"All\",\"Announcements\",\"Product\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/ionic.io\/blog\/introducing-trapeze#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/ionic.io\/blog\/introducing-trapeze\",\"url\":\"https:\/\/ionic.io\/blog\/introducing-trapeze\",\"name\":\"Introducing Trapeze: Easy iOS and Android Project Configuration\",\"isPartOf\":{\"@id\":\"https:\/\/ionic.io\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/ionic.io\/blog\/introducing-trapeze#primaryimage\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/introducing-trapeze#primaryimage\"},\"thumbnailUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/01\/trapeze-ionic-feature-image.png\",\"datePublished\":\"2023-01-12T16:55:24+00:00\",\"dateModified\":\"2023-01-12T16:55:44+00:00\",\"description\":\"Trapeze is an open-source project that lets you manage native & cross-platform mobile projects from a YAML-based configuration-file format.\",\"breadcrumb\":{\"@id\":\"https:\/\/ionic.io\/blog\/introducing-trapeze#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/ionic.io\/blog\/introducing-trapeze\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/introducing-trapeze#primaryimage\",\"url\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/01\/trapeze-ionic-feature-image.png\",\"contentUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/01\/trapeze-ionic-feature-image.png\",\"width\":2240,\"height\":1120,\"caption\":\"Trapeze\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/ionic.io\/blog\/introducing-trapeze#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/ionic.io\/blog\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Introducing Trapeze: Easy iOS and Android Project Configuration\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/ionic.io\/blog\/#website\",\"url\":\"https:\/\/ionic.io\/blog\/\",\"name\":\"ionic.io\/blog\",\"description\":\"Build amazing native and progressive web apps with the web\",\"publisher\":{\"@id\":\"https:\/\/ionic.io\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/ionic.io\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/ionic.io\/blog\/#organization\",\"name\":\"Ionic\",\"url\":\"https:\/\/ionic.io\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png\",\"contentUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png\",\"width\":1920,\"height\":854,\"caption\":\"Ionic\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/ionicframework\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/91f360cffbd804a464b0c4a87b5c5f1e\",\"name\":\"Max Lynch\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2018\/05\/max-avatar-150x150.jpg\",\"contentUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2018\/05\/max-avatar-150x150.jpg\",\"caption\":\"Max Lynch\"},\"description\":\"CEO\",\"sameAs\":[\"http:\/\/twitter.com\/maxlynch\",\"https:\/\/x.com\/maxlynch\"],\"url\":\"https:\/\/ionic.io\/blog\/author\/max\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Introducing Trapeze: Easy iOS and Android Project Configuration","description":"Trapeze is an open-source project that lets you manage native & cross-platform mobile projects from a YAML-based configuration-file format.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/ionic.io\/blog\/introducing-trapeze","og_locale":"en_US","og_type":"article","og_title":"Introducing Trapeze: Easy iOS and Android Project Configuration","og_description":"Trapeze is an open-source project that lets you manage native & cross-platform mobile projects from a YAML-based configuration-file format.","og_url":"https:\/\/ionic.io\/blog\/introducing-trapeze","og_site_name":"Ionic Blog","article_published_time":"2023-01-12T16:55:24+00:00","article_modified_time":"2023-01-12T16:55:44+00:00","og_image":[{"width":2240,"height":1120,"url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/01\/trapeze-ionic-feature-image.png","type":"image\/png"}],"author":"Max Lynch","twitter_card":"summary_large_image","twitter_creator":"@maxlynch","twitter_site":"@ionicframework","twitter_misc":{"Written by":"Max Lynch"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/ionic.io\/blog\/introducing-trapeze#article","isPartOf":{"@id":"https:\/\/ionic.io\/blog\/introducing-trapeze"},"author":{"name":"Max Lynch","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/91f360cffbd804a464b0c4a87b5c5f1e"},"headline":"Introducing Trapeze: Easy iOS and Android Project Configuration","datePublished":"2023-01-12T16:55:24+00:00","dateModified":"2023-01-12T16:55:44+00:00","mainEntityOfPage":{"@id":"https:\/\/ionic.io\/blog\/introducing-trapeze"},"wordCount":756,"commentCount":0,"publisher":{"@id":"https:\/\/ionic.io\/blog\/#organization"},"image":{"@id":"https:\/\/ionic.io\/blog\/introducing-trapeze#primaryimage"},"thumbnailUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/01\/trapeze-ionic-feature-image.png","keywords":["trapeze"],"articleSection":["All","Announcements","Product"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/ionic.io\/blog\/introducing-trapeze#respond"]}]},{"@type":"WebPage","@id":"https:\/\/ionic.io\/blog\/introducing-trapeze","url":"https:\/\/ionic.io\/blog\/introducing-trapeze","name":"Introducing Trapeze: Easy iOS and Android Project Configuration","isPartOf":{"@id":"https:\/\/ionic.io\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/ionic.io\/blog\/introducing-trapeze#primaryimage"},"image":{"@id":"https:\/\/ionic.io\/blog\/introducing-trapeze#primaryimage"},"thumbnailUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/01\/trapeze-ionic-feature-image.png","datePublished":"2023-01-12T16:55:24+00:00","dateModified":"2023-01-12T16:55:44+00:00","description":"Trapeze is an open-source project that lets you manage native & cross-platform mobile projects from a YAML-based configuration-file format.","breadcrumb":{"@id":"https:\/\/ionic.io\/blog\/introducing-trapeze#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/ionic.io\/blog\/introducing-trapeze"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/introducing-trapeze#primaryimage","url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/01\/trapeze-ionic-feature-image.png","contentUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/01\/trapeze-ionic-feature-image.png","width":2240,"height":1120,"caption":"Trapeze"},{"@type":"BreadcrumbList","@id":"https:\/\/ionic.io\/blog\/introducing-trapeze#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/ionic.io\/blog"},{"@type":"ListItem","position":2,"name":"Introducing Trapeze: Easy iOS and Android Project Configuration"}]},{"@type":"WebSite","@id":"https:\/\/ionic.io\/blog\/#website","url":"https:\/\/ionic.io\/blog\/","name":"ionic.io\/blog","description":"Build amazing native and progressive web apps with the web","publisher":{"@id":"https:\/\/ionic.io\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/ionic.io\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/ionic.io\/blog\/#organization","name":"Ionic","url":"https:\/\/ionic.io\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png","contentUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png","width":1920,"height":854,"caption":"Ionic"},"image":{"@id":"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/ionicframework"]},{"@type":"Person","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/91f360cffbd804a464b0c4a87b5c5f1e","name":"Max Lynch","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/image\/","url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2018\/05\/max-avatar-150x150.jpg","contentUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2018\/05\/max-avatar-150x150.jpg","caption":"Max Lynch"},"description":"CEO","sameAs":["http:\/\/twitter.com\/maxlynch","https:\/\/x.com\/maxlynch"],"url":"https:\/\/ionic.io\/blog\/author\/max"}]}},"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2023\/01\/trapeze-ionic-feature-image.png","_links":{"self":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/4639","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/comments?post=4639"}],"version-history":[{"count":10,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/4639\/revisions"}],"predecessor-version":[{"id":4657,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/4639\/revisions\/4657"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/media\/4625"}],"wp:attachment":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/media?parent=4639"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/categories?post=4639"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/tags?post=4639"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}