diff --git a/CHANGELOG.md b/CHANGELOG.md index abd6a0fd2..502dd22cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ _None_ ### New Features -_None_ +* Introduce new `ios_send_app_size_metrics` and `android_send_app_size_metrics` actions. [#364] ### Bug Fixes diff --git a/Gemfile.lock b/Gemfile.lock index 9f9e37773..23b841d63 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -12,6 +12,7 @@ PATH nokogiri (~> 1.11) octokit (~> 4.18) parallel (~> 1.14) + plist (~> 3.1) progress_bar (~> 1.3) rake (>= 12.3, < 14.0) rake-compiler (~> 1.0) @@ -427,4 +428,4 @@ DEPENDENCIES yard BUNDLED WITH - 2.3.11 + 2.3.13 diff --git a/fastlane-plugin-wpmreleasetoolkit.gemspec b/fastlane-plugin-wpmreleasetoolkit.gemspec index da2858439..598bd3ceb 100644 --- a/fastlane-plugin-wpmreleasetoolkit.gemspec +++ b/fastlane-plugin-wpmreleasetoolkit.gemspec @@ -29,6 +29,7 @@ Gem::Specification.new do |spec| spec.add_dependency 'nokogiri', '~> 1.11' # Needed for AndroidLocalizeHelper spec.add_dependency 'octokit', '~> 4.18' spec.add_dependency 'buildkit', '~> 1.5' + spec.add_dependency 'plist', '~> 3.1' spec.add_dependency 'git', '~> 1.3' spec.add_dependency 'jsonlint', '~> 0.3' spec.add_dependency 'rake', '>= 12.3', '< 14.0' diff --git a/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_send_app_size_metrics.rb b/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_send_app_size_metrics.rb new file mode 100644 index 000000000..3dbec910f --- /dev/null +++ b/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_send_app_size_metrics.rb @@ -0,0 +1,212 @@ +require_relative '../../helper/app_size_metrics_helper' + +module Fastlane + module Actions + class AndroidSendAppSizeMetricsAction < Action + def self.run(params) + # Check input parameters + api_url = URI(params[:api_url]) + api_token = params[:api_token] + if (api_token.nil? || api_token.empty?) && !api_url.is_a?(URI::File) + UI.user_error!('An API token is required when using an `api_url` with a scheme other than `file://`') + end + + # Build the payload base + metrics_helper = Fastlane::Helper::AppSizeMetricsHelper.new( + Platform: 'Android', + 'App Name': params[:app_name], + 'App Version': params[:app_version_name], + 'Version Code': params[:app_version_code], + 'Product Flavor': params[:product_flavor], + 'Build Type': params[:build_type], + Source: params[:source] + ) + metrics_helper.add_metric(name: 'AAB File Size', value: File.size(params[:aab_path])) + + # Add device-specific 'splits' metrics to the payload if a `:include_split_sizes` is enabled + if params[:include_split_sizes] + check_bundletool_installed! + apkanalyzer_bin = params[:apkanalyzer_binary] || find_apkanalyzer_binary! + UI.message("[App Size Metrics] Generating the various APK splits from #{params[:aab_path]}...") + Dir.mktmpdir('release-toolkit-android-app-size-metrics') do |tmp_dir| + Action.sh('bundletool', 'build-apks', '--bundle', params[:aab_path], '--output-format', 'DIRECTORY', '--output', tmp_dir) + apks = Dir.glob('splits/*.apk', base: tmp_dir).map { |f| File.join(tmp_dir, f) } + UI.message("[App Size Metrics] Generated #{apks.length} APKs.") + + apks.each do |apk| + UI.message("[App Size Metrics] Computing file and download size of #{File.basename(apk)}...") + split_name = File.basename(apk, '.apk') + file_size = Action.sh(apkanalyzer_bin, 'apk', 'file-size', apk, print_command: false, print_command_output: false).chomp.to_i + download_size = Action.sh(apkanalyzer_bin, 'apk', 'download-size', apk, print_command: false, print_command_output: false).chomp.to_i + metrics_helper.add_metric(name: 'APK File Size', value: file_size, metadata: { split: split_name }) + metrics_helper.add_metric(name: 'Download Size', value: download_size, metadata: { split: split_name }) + end + + UI.message('[App Size Metrics] Done computing splits sizes.') + end + end + + # Send the payload + metrics_helper.send_metrics( + to: api_url, + api_token: api_token, + use_gzip: params[:use_gzip_content_encoding] + ) + end + + def self.check_bundletool_installed! + Action.sh('command', '-v', 'bundletool', print_command: false, print_command_output: false) + rescue StandardError + UI.user_error!('bundletool is required to build the split APKs. Install it with `brew install bundletool`') + raise + end + + def self.find_apkanalyzer_binary + sdk_root = ENV['ANDROID_SDK_ROOT'] || ENV['ANDROID_HOME'] + if sdk_root + pattern = File.join(sdk_root, 'cmdline-tools', '{latest,tools}', 'bin', 'apkanalyzer') + apkanalyzer_bin = Dir.glob(pattern).find { |path| File.executable?(path) } + end + apkanalyzer_bin || Action.sh('command', '-v', 'apkanalyzer', print_command_output: false) { |_| nil } + end + + def self.find_apkanalyzer_binary! + apkanalyzer_bin = find_apkanalyzer_binary + UI.user_error!('Unable to find `apkanalyzer` executable in `$PATH` nor `$ANDROID_SDK_ROOT`. Make sure you installed the Android SDK Command-line Tools') if apkanalyzer_bin.nil? + apkanalyzer_bin + end + + ##################################################### + # @!group Documentation + ##################################################### + + def self.description + 'Send Android app size metrics to our metrics server' + end + + def self.details + <<~DETAILS + Send Android app size metrics to our metrics server. + + See https://github.com/Automattic/apps-metrics for the API contract expected by the Metrics server you will send those metrics to. + + Tip: If you provide a `file://` URL for the `api_url`, the action will write the payload on disk at the specified path instead of sending + the data to a endpoint over network. This can be useful e.g. to inspect the payload and debug it, or to store the metrics data as CI artefacts. + DETAILS + end + + def self.available_options + [ + FastlaneCore::ConfigItem.new( + key: :api_url, + env_name: 'FL_ANDROID_SEND_APP_SIZE_METRICS_API_URL', + description: 'The endpoint API URL to publish metrics to. (Note: you can also point to a `file://` URL to write the payload to a file instead)', + type: String, + optional: false + ), + FastlaneCore::ConfigItem.new( + key: :api_token, + env_name: 'FL_ANDROID_SEND_APP_SIZE_METRICS_API_TOKEN', + description: 'The bearer token to call the API. Required, unless `api_url` is a `file://` URL', + type: String, + optional: true + ), + FastlaneCore::ConfigItem.new( + key: :use_gzip_content_encoding, + env_name: 'FL_ANDROID_SEND_APP_SIZE_METRICS_USE_GZIP_CONTENT_ENCODING', + description: 'Specify that we should use `Content-Encoding: gzip` and gzip the body when sending the request', + type: FastlaneCore::Boolean, + default_value: true + ), + FastlaneCore::ConfigItem.new( + key: :app_name, + env_name: 'FL_ANDROID_SEND_APP_SIZE_METRICS_APP_NAME', + description: 'The name of the app for which we are publishing metrics, to help filter by app in the dashboard', + type: String, + optional: false + ), + FastlaneCore::ConfigItem.new( + key: :app_version_name, + env_name: 'FL_ANDROID_SEND_APP_SIZE_METRICS_APP_VERSION_NAME', + description: 'The version name of the app for which we are publishing metrics, to help filter by version in the dashboard', + type: String, + optional: false + ), + FastlaneCore::ConfigItem.new( + key: :app_version_code, + env_name: 'FL_ANDROID_SEND_APP_SIZE_METRICS_APP_VERSION_CODE', + description: 'The version code of the app for which we are publishing metrics, to help filter by version in the dashboard', + type: Integer, + optional: true + ), + FastlaneCore::ConfigItem.new( + key: :product_flavor, + env_name: 'FL_ANDROID_SEND_APP_SIZE_METRICS_PRODUCT_FLAVOR', + description: 'The product flavor for which we are publishing metrics, to help filter by flavor in the dashboard. E.g. `Vanilla`, `Jalapeno`, `Wasabi`', + type: String, + optional: true + ), + FastlaneCore::ConfigItem.new( + key: :build_type, + env_name: 'FL_ANDROID_SEND_APP_SIZE_METRICS_BUILD_TYPE', + description: 'The build type for which we are publishing metrics, to help filter by build type in the dashboard. E.g. `Debug`, `Release`', + type: String, + optional: true + ), + FastlaneCore::ConfigItem.new( + key: :source, + env_name: 'FL_ANDROID_SEND_APP_SIZE_METRICS_SOURCE', + description: 'The type of event at the origin of that build, to help filter data in the dashboard. E.g. `pr`, `beta`, `final-release`', + type: String, + optional: true + ), + FastlaneCore::ConfigItem.new( + key: :aab_path, + env_name: 'FL_ANDROID_SEND_APP_SIZE_METRICS_AAB_PATH', + description: 'The path to the .aab to extract size information from', + type: String, + optional: false, + verify_block: proc do |value| + UI.user_error!('You must provide an path to an existing `.aab` file') unless File.exist?(value) + end + ), + FastlaneCore::ConfigItem.new( + key: :include_split_sizes, + env_name: 'FL_ANDROID_SEND_APP_SIZE_METRICS_INCLUDE_SPLIT_SIZES', + description: 'Indicate if we should use `bundletool` and `apkanalyzer` to also compute and send "split apk" sizes per architecture. ' \ + + 'Setting this to `true` adds a bit of extra time to generate the `.apk` and extract the data, but provides more detailed metrics', + type: FastlaneCore::Boolean, + default_value: true + ), + FastlaneCore::ConfigItem.new( + key: :apkanalyzer_binary, + env_name: 'FL_ANDROID_SEND_APP_SIZE_METRICS_APKANALYZER_BINARY', + description: 'The path to the `apkanalyzer` binary to use. If not provided explicitly, we will use `$PATH` and `$ANDROID_SDK_HOME` to try to find it', + type: String, + default_value: find_apkanalyzer_binary, + default_value_dynamic: true, + verify_block: proc do |value| + UI.user_error!('You must provide a path to an existing executable for `apkanalyzer`') unless File.executable?(value) + end + ), + ] + end + + def self.return_type + :integer + end + + def self.return_value + 'The HTTP return code from the call. Expect a 201 when new metrics were received successfully and entries created in the database' + end + + def self.authors + ['automattic'] + end + + def self.is_supported?(platform) + platform == :android + end + end + end +end diff --git a/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_send_app_size_metrics.rb b/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_send_app_size_metrics.rb new file mode 100644 index 000000000..b01f54908 --- /dev/null +++ b/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_send_app_size_metrics.rb @@ -0,0 +1,165 @@ +require 'plist' +require_relative '../../helper/app_size_metrics_helper' + +module Fastlane + module Actions + class IosSendAppSizeMetricsAction < Action + def self.run(params) + # Check input parameters + api_url = URI(params[:api_url]) + api_token = params[:api_token] + if (api_token.nil? || api_token.empty?) && !api_url.is_a?(URI::File) + UI.user_error!('An API token is required when using an `api_url` with a scheme other than `file://`') + end + + # Build the payload base + metrics_helper = Fastlane::Helper::AppSizeMetricsHelper.new( + Platform: 'iOS', + 'App Name': params[:app_name], + 'App Version': params[:app_version], + 'Build Type': params[:build_type], + Source: params[:source] + ) + metrics_helper.add_metric(name: 'File Size', value: File.size(params[:ipa_path])) + + # Add app-thinning metrics to the payload if a `.plist` is provided + app_thinning_plist_path = params[:app_thinning_plist_path] || File.join(File.dirname(params[:ipa_path]), 'app-thinning.plist') + if File.exist?(app_thinning_plist_path) + plist = Plist.parse_xml(app_thinning_plist_path) + plist['variants'].each do |_key, variant| + variant_descriptors = variant['variantDescriptors'] || [{ 'device' => 'Universal' }] + variant_descriptors.each do |desc| + variant_metadata = { device: desc['device'], 'OS Version': desc['os-version'] } + metrics_helper.add_metric(name: 'Download Size', value: variant['sizeCompressedApp'], metadata: variant_metadata) + metrics_helper.add_metric(name: 'Install Size', value: variant['sizeUncompressedApp'], metadata: variant_metadata) + end + end + end + + # Send the payload + metrics_helper.send_metrics( + to: api_url, + api_token: api_token, + use_gzip: params[:use_gzip_content_encoding] + ) + end + + ##################################################### + # @!group Documentation + ##################################################### + + def self.description + 'Send iOS app size metrics to our metrics server' + end + + def self.details + <<~DETAILS + Send iOS app size metrics to our metrics server. + + In order to get Xcode generate the `app-thinning.plist` file (during `gym` and the export of the `.xcarchive`), you need to: + (1) Use either `ad-hoc`, `enterprise` or `development` export method (in particular, won't work with `app-store`), + (2) Provide `thinning: ''` as part of your `export_options` of `gym` (or in your `options.plist` file if you use raw `xcodebuild`) + See https://help.apple.com/xcode/mac/11.0/index.html#/devde46df08a + + For builds exported with the `app-store` method, `xcodebuild` won't generate an `app-thinning.plist` file; so you will only be able to get + the Universal `.ipa` file size as a metric, but won't get the per-device, broken-down install and download sizes for each thinned variant. + + See https://github.com/Automattic/apps-metrics for the API contract expected by the Metrics server you are expected to send those metrics to. + + Tip: If you provide a `file://` URL for the `api_url`, the action will write the payload on disk at the specified path instead of sending + the data to a endpoint over network. This can be useful e.g. to inspect the payload and debug it, or to store the metrics data as CI artefacts. + DETAILS + end + + def self.available_options + [ + FastlaneCore::ConfigItem.new( + key: :api_url, + env_name: 'FL_IOS_SEND_APP_SIZE_METRICS_API_URL', + description: 'The endpoint API URL to publish metrics to. (Note: you can also point to a `file://` URL to write the payload to a file instead)', + type: String, + optional: false + ), + FastlaneCore::ConfigItem.new( + key: :api_token, + env_name: 'FL_IOS_SEND_APP_SIZE_METRICS_API_TOKEN', + description: 'The bearer token to call the API. Required, unless `api_url` is a `file://` URL', + type: String, + optional: true + ), + FastlaneCore::ConfigItem.new( + key: :use_gzip_content_encoding, + env_name: 'FL_IOS_SEND_APP_SIZE_METRICS_USE_GZIP_CONTENT_ENCODING', + description: 'Specify that we should use `Content-Encoding: gzip` and gzip the body when sending the request', + type: FastlaneCore::Boolean, + default_value: true + ), + FastlaneCore::ConfigItem.new( + key: :app_name, + env_name: 'FL_IOS_SEND_APP_SIZE_METRICS_APP_NAME', + description: 'The name of the app for which we are publishing metrics, to help with filtering and grouping', + type: String, + optional: false + ), + FastlaneCore::ConfigItem.new( + key: :app_version, + env_name: 'FL_IOS_SEND_APP_SIZE_METRICS_APP_VERSION', + description: 'The version of the app for which we are publishing metrics, to help with filtering and grouping', + type: String, + optional: false + ), + FastlaneCore::ConfigItem.new( + key: :build_type, + env_name: 'FL_IOS_SEND_APP_SIZE_METRICS_BUILD_TYPE', + description: 'The build configuration for which we are publishing metrics, to help with filtering and grouping. E.g. `Debug`, `Release`', + type: String, + optional: true + ), + FastlaneCore::ConfigItem.new( + key: :source, + env_name: 'FL_IOS_SEND_APP_SIZE_METRICS_SOURCE', + description: 'The type of event at the origin of that build, to help with filtering and grouping. E.g. `pr`, `beta`, `final-release`', + type: String, + optional: true + ), + FastlaneCore::ConfigItem.new( + key: :ipa_path, + env_name: 'FL_IOS_SEND_APP_SIZE_METRICS_IPA_PATH', + description: 'The path to the `.ipa` to extract size information from', + type: String, + optional: false, + default_value: Actions.lane_context[SharedValues::IPA_OUTPUT_PATH], + verify_block: proc do |value| + UI.user_error!('You must provide an path to an existing `.ipa` file') unless File.exist?(value) + end + ), + FastlaneCore::ConfigItem.new( + key: :app_thinning_plist_path, + env_name: 'FL_IOS_SEND_APP_SIZE_METRICS_APP_THINNING_PLIST_PATH', + description: 'The path to the `app-thinning.plist` file to extract thinning size information from. ' \ + + 'By default, will try to use the `app-thinning.plist` file next to the `ipa_path`, if that file exists', + type: String, + optional: true, + default_value_dynamic: true + ), + ] + end + + def self.return_type + :integer + end + + def self.return_value + 'The HTTP return code from the call. Expect a 201 when new metrics were received successfully and entries created in the database' + end + + def self.authors + ['automattic'] + end + + def self.is_supported?(platform) + platform == :ios + end + end + end +end diff --git a/lib/fastlane/plugin/wpmreleasetoolkit/helper/app_size_metrics_helper.rb b/lib/fastlane/plugin/wpmreleasetoolkit/helper/app_size_metrics_helper.rb new file mode 100644 index 000000000..f200a160a --- /dev/null +++ b/lib/fastlane/plugin/wpmreleasetoolkit/helper/app_size_metrics_helper.rb @@ -0,0 +1,95 @@ +require 'json' +require 'net/http' +require 'zlib' + +module Fastlane + module Helper + # A helper class to build an App Size Metrics payload and send it to a server (or write it to disk) + # + # The payload generated (and sent) by this helper conforms to the API for grouped metrics described in + # https://github.com/Automattic/apps-metrics + # + class AppSizeMetricsHelper + # @param [Hash] metadata Metadata common to all the metrics. Can be any arbitrary set of key/value pairs. + # + def initialize(metadata = {}) + self.metadata = metadata + @metrics = [] + end + + # Sets the metadata common to the whole group of metrics in the payload being built by this helper instance + # + # @param [Hash] hash The metadata common to all the metrics of the payload built by that helper instance. Can be any arbitrary set of key/value pairs + # + def metadata=(hash) + @metadata = (hash.compact || {}).map { |key, value| { name: key.to_s, value: value } } + end + + # Adds a single metric to the group of metrics + # + # @param [String] name The metric name + # @param [Integer] value The metric value + # @param [Hash] metadata The arbitrary dictionary of metadata to associate to that metric entry + # + def add_metric(name:, value:, metadata: nil) + metric = { name: name, value: value } + metadata = metadata&.compact || {} # Remove nil values if any (and use empty Hash if nil was provided) + metric[:meta] = metadata.map { |meta_key, meta_value| { name: meta_key.to_s, value: meta_value } } unless metadata.empty? + @metrics.append(metric) + end + + def to_h + { + meta: @metadata, + metrics: @metrics + } + end + + # Send the metrics to the given App Metrics endpoint. + # + # Must conform to the API described in https://github.com/Automattic/apps-metrics/wiki/Queue-Group-of-Metrics + # + # @param [String,URI] to The URL of the App Metrics service, or a `file://` URL to write the payload to disk + # @param [String] api_token The API bearer token to use to register the metric. + # @return [Integer] the HTTP response code + # + def send_metrics(to:, api_token:, use_gzip: true) + uri = URI(to) + json_payload = use_gzip ? Zlib.gzip(to_h.to_json) : to_h.to_json + + # Allow using a `file:` URI for debugging + if uri.is_a?(URI::File) + UI.message("Writing metrics payload to file #{uri.path} (instead of sending it to a remote API endpoint)") + File.write(uri.path, json_payload) + return 201 # To make it easy at call site to check for pseudo-status code 201 even in non-HTTP cases + end + + UI.message("Sending metrics to #{uri}...") + headers = { + Authorization: "Bearer #{api_token}", + Accept: 'application/json', + 'Content-Type': 'application/json' + } + headers[:'Content-Encoding'] = 'gzip' if use_gzip + + request = Net::HTTP::Post.new(uri, headers) + request.body = json_payload + + response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http| + http.request(request) + end + + if response.is_a?(Net::HTTPSuccess) + UI.success("Metrics sent. (#{response.code} #{response.message})") + else + UI.error("Metrics failed to send. Received: #{response.code} #{response.message}") + UI.message("Request was #{request.method} to #{request.uri}") + UI.message("Request headers were: #{headers}") + UI.message("Request body was #{request.body.length} bytes") + UI.message("Response was #{response.body}") + end + response.code.to_i + end + end + end +end diff --git a/spec/android_send_app_size_metrics_spec.rb b/spec/android_send_app_size_metrics_spec.rb new file mode 100644 index 000000000..9a51b8a58 --- /dev/null +++ b/spec/android_send_app_size_metrics_spec.rb @@ -0,0 +1,137 @@ +require_relative './spec_helper' + +describe Fastlane::Actions::AndroidSendAppSizeMetricsAction do + let(:test_data_dir) { File.join(File.dirname(__FILE__), 'test-data', 'app_size_metrics') } + + def test_app_size_action(fake_aab_size:, fake_apks:, expected_payload:, **other_action_args) + in_tmp_dir do |tmp_dir| + # Arrange + output_file = File.join(tmp_dir, 'output-payload') + aab_path = File.join(tmp_dir, 'fake.aab') + File.write(aab_path, '-fake-aab-file-') + allow(File).to receive(:size).with(aab_path).and_return(fake_aab_size) + + if other_action_args[:include_split_sizes] != false + # Arrange: fake that apkanalyzer exists + apkanalyzer_bin = File.join('__ANDROID_SDK_ROOT__FOR_TESTS__', 'cmdline-tools', 'latest', 'bin', 'apkanalyzer') + allow(described_class).to receive(:find_apkanalyzer_binary).and_return(apkanalyzer_bin) + allow(File).to receive(:executable?).with(apkanalyzer_bin).and_return(true) + + # Arrange: fake that bundletool exists and mock its call to create fake apks with corresponding apkanalyzer calls mocks + allow(Fastlane::Action).to receive(:sh).with('command', '-v', 'bundletool', anything) + allow(Fastlane::Action).to receive(:sh).with('bundletool', 'build-apks', '--bundle', aab_path, '--output-format', 'DIRECTORY', '--output', anything) do |*args| + bundletool_tmpdir = args.last + FileUtils.mkdir(File.join(bundletool_tmpdir, 'splits')) + fake_apks.each do |apk_name, sizes| + apk_path = File.join(bundletool_tmpdir, 'splits', apk_name.to_s) + File.write(apk_path, "Fake APK file (#{sizes})") + allow(Fastlane::Action).to receive(:sh).with(apkanalyzer_bin, 'apk', 'file-size', apk_path, anything).and_return(sizes[0].to_s) + allow(Fastlane::Action).to receive(:sh).with(apkanalyzer_bin, 'apk', 'download-size', apk_path, anything).and_return(sizes[1].to_s) + end + end + end + + # Act + code = run_described_fastlane_action( + api_url: File.join('file://localhost/', output_file), + aab_path: aab_path, + **other_action_args + ) + + # Asserts + expect(code).to eq(201) + expect(File).to exist(output_file) + gzip_disabled = other_action_args[:use_gzip_content_encoding] == false + generated_payload = gzip_disabled ? File.read(output_file) : Zlib::GzipReader.open(output_file, &:read) + # Compare the payloads as pretty-formatted JSON, to make the diff in test failures more readable if one happen + expect(JSON.pretty_generate(JSON.parse(generated_payload))).to eq(JSON.pretty_generate(expected_payload)), 'Decompressed JSON payload was not as expected' + # Compare the payloads as raw uncompressed data as a final check + expect(generated_payload).to eq(expected_payload.to_json) + end + end + + context 'when `include_split_sizes` is turned off' do + it 'generates the expected payload compressed by default' do + expected = { + meta: [ + { name: 'Platform', value: 'Android' }, + { name: 'App Name', value: 'my-app' }, + { name: 'App Version', value: '10.2-rc-3' }, + { name: 'Product Flavor', value: 'Vanilla' }, + { name: 'Build Type', value: 'Release' }, + { name: 'Source', value: 'unit-test' }, + ], + metrics: [ + { name: 'AAB File Size', value: 123_456 }, + ] + } + + test_app_size_action( + fake_aab_size: 123_456, + fake_apks: {}, + expected_payload: expected, + app_name: 'my-app', + app_version_name: '10.2-rc-3', + product_flavor: 'Vanilla', + build_type: 'Release', + source: 'unit-test', + include_split_sizes: false + ) + end + + it 'generates the expected payload uncompressed when disabling gzip' do + expected = { + meta: [ + { name: 'Platform', value: 'Android' }, + { name: 'App Name', value: 'my-app' }, + { name: 'App Version', value: '10.2-rc-3' }, + { name: 'Product Flavor', value: 'Vanilla' }, + { name: 'Build Type', value: 'Release' }, + { name: 'Source', value: 'unit-test' }, + ], + metrics: [ + { name: 'AAB File Size', value: 123_456 }, + ] + } + + test_app_size_action( + fake_aab_size: 123_456, + fake_apks: {}, + expected_payload: expected, + app_name: 'my-app', + app_version_name: '10.2-rc-3', + product_flavor: 'Vanilla', + build_type: 'Release', + source: 'unit-test', + include_split_sizes: false, + use_gzip_content_encoding: false + ) + end + end + + context 'when keeping the default value of `include_split_sizes` turned on' do + it 'generates the expected payload containing the aab file size and optimized split sizes' do + expected_fixture = File.join(test_data_dir, 'android-metrics-payload.json') + expected = JSON.parse(File.read(expected_fixture)) + + test_app_size_action( + fake_aab_size: 987_654_321, + fake_apks: { + 'base-arm64_v8a.apk': [164_080, 64_080], + 'base-arm64_v8a_2.apk': [164_082, 64_082], + 'base-armeabi.apk': [150_000, 50_000], + 'base-armeabi_2.apk': [150_002, 50_002], + 'base-armeabi_v7a.apk': [150_070, 50_070], + 'base-armeabi_v7a_2.apk': [150_072, 50_072] + }, + expected_payload: expected, + app_name: 'wordpress', + app_version_name: '19.8-rc-3', + app_version_code: 1214, + product_flavor: 'Vanilla', + build_type: 'Release', + source: 'unit-test' + ) + end + end +end diff --git a/spec/app_size_metrics_helper_spec.rb b/spec/app_size_metrics_helper_spec.rb new file mode 100644 index 000000000..83434cf78 --- /dev/null +++ b/spec/app_size_metrics_helper_spec.rb @@ -0,0 +1,153 @@ +require_relative './spec_helper' + +describe Fastlane::Helper::AppSizeMetricsHelper do + describe '#to_h' do + it 'generates the right payload from raw data' do + metrics_helper = described_class.new({ + 'Group Metadata 1': 'Group Value 1', + 'Group Metadata 2': 'Group Value 2' + }) + metrics_helper.add_metric(name: 'Metric 1', value: 12_345, metadata: { m1a: 'Metric 1 Metadata A' }) + metrics_helper.add_metric(name: 'Metric 2', value: 67_890) + metrics_helper.add_metric(name: 'Metric 3', value: 13_579, metadata: { m3a: 'Metric 3 Metadata A', m3b: 'Metric 3 Metadata B' }) + + expected_hash = { + meta: [ + { name: 'Group Metadata 1', value: 'Group Value 1' }, + { name: 'Group Metadata 2', value: 'Group Value 2' }, + ], + metrics: [ + { name: 'Metric 1', value: 12_345, meta: [{ name: 'm1a', value: 'Metric 1 Metadata A' }] }, + { name: 'Metric 2', value: 67_890 }, + { name: 'Metric 3', value: 13_579, meta: [{ name: 'm3a', value: 'Metric 3 Metadata A' }, { name: 'm3b', value: 'Metric 3 Metadata B' }] }, + ] + } + expect(metrics_helper.to_h).to eq(expected_hash) + end + + it 'removes `nil` values in metadata' do + metrics_helper = described_class.new({ + 'Group Metadata 1': 'Group Value 1', + 'Group Metadata 2': nil, + 'Group Metadata 3': 'Group Value 3' + }) + metrics_helper.add_metric(name: 'Metric 1', value: 12_345, metadata: { m1a: 'Metric 1 Metadata A', m1b: nil, m1c: 'Metric 1 Metadata C' }) + metrics_helper.add_metric(name: 'Metric 2', value: 67_890, metadata: { m2a: nil }) + metrics_helper.add_metric(name: 'Metric 3', value: 13_579, metadata: { m3a: 'Metric 3 Metadata A', m3b: 'Metric 3 Metadata B' }) + + expected_hash = { + meta: [ + { name: 'Group Metadata 1', value: 'Group Value 1' }, + { name: 'Group Metadata 3', value: 'Group Value 3' }, + ], + metrics: [ + { name: 'Metric 1', value: 12_345, meta: [{ name: 'm1a', value: 'Metric 1 Metadata A' }, { name: 'm1c', value: 'Metric 1 Metadata C' }] }, + { name: 'Metric 2', value: 67_890 }, + { name: 'Metric 3', value: 13_579, meta: [{ name: 'm3a', value: 'Metric 3 Metadata A' }, { name: 'm3b', value: 'Metric 3 Metadata B' }] }, + ] + } + expect(metrics_helper.to_h).to eq(expected_hash) + end + end + + describe '#send_metrics' do + let(:metrics_helper) do + metrics_helper = described_class.new({ + 'Group Metadata 1': 'Group Value 1', + 'Group Metadata 2': 'Group Value 2' + }) + metrics_helper.add_metric(name: 'Metric 1', value: 12_345, metadata: { m1a: 'Metric 1 Metadata A' }) + metrics_helper.add_metric(name: 'Metric 2', value: 67_890) + metrics_helper.add_metric(name: 'Metric 3', value: 13_579, metadata: { m3a: 'Metric 3 Metadata A', m3b: 'Metric 3 Metadata B' }) + metrics_helper + end + let(:expected_data) do + { + meta: [ + { name: 'Group Metadata 1', value: 'Group Value 1' }, + { name: 'Group Metadata 2', value: 'Group Value 2' }, + ], + metrics: [ + { name: 'Metric 1', value: 12_345, meta: [{ name: 'm1a', value: 'Metric 1 Metadata A' }] }, + { name: 'Metric 2', value: 67_890 }, + { name: 'Metric 3', value: 13_579, meta: [{ name: 'm3a', value: 'Metric 3 Metadata A' }, { name: 'm3b', value: 'Metric 3 Metadata B' }] }, + ] + }.to_json + end + + context 'when using file:// scheme for the URL' do + it 'writes the payload uncompressed to a file when disabling gzip' do + in_tmp_dir do |tmp_dir| + output_file = File.join(tmp_dir, 'payload.json') + file_url = File.join('file://localhost/', output_file) + + code = metrics_helper.send_metrics(to: file_url, api_token: nil, use_gzip: false) + + expect(code).to eq(201) + expect(File).to exist(output_file) + uncompressed_data = File.read(output_file) + expect(uncompressed_data).to eq(expected_data) + end + end + + it 'writes the payload compressed to a file when enabling gzip' do + in_tmp_dir do |tmp_dir| + output_file = File.join(tmp_dir, 'payload.json.gz') + file_url = File.join('file://localhost/', output_file) + + code = metrics_helper.send_metrics(to: file_url, api_token: nil, use_gzip: true) + + expect(code).to eq(201) + expect(File).to exist(output_file) + uncompressed_data = Zlib::GzipReader.open(output_file, &:read) + expect(uncompressed_data).to eq(expected_data) + end + end + end + + context 'when using non-file:// scheme for the URL' do + let(:api_url) { 'https://fake-metrics-server/api/grouped-metrics' } + let(:token) { 'fake#tokn' } + + it 'sends the payload uncompressed to the server and with the right headers when disabling gzip' do + expected_headers = { + Authorization: "Bearer #{token}", + Accept: 'application/json', + 'Content-Type': 'application/json' + } + last_received_body = nil + stub = stub_request(:post, api_url).with(headers: expected_headers) do |req| + last_received_body = req.body + end.to_return(status: 201) + + code = metrics_helper.send_metrics(to: api_url, api_token: token, use_gzip: false) + + expect(code).to eq(201) + expect(stub).to have_been_made.once + expect(last_received_body).to eq(expected_data) + end + + it 'sends the payload compressed to the server and with the right headers when enabling gzip' do + expected_headers = { + Authorization: "Bearer #{token}", + Accept: 'application/json', + 'Content-Type': 'application/json', + 'Content-Encoding': 'gzip' + } + last_received_body = nil + stub = stub_request(:post, api_url).with(headers: expected_headers) do |req| + last_received_body = req.body + end.to_return(status: 201) + + code = metrics_helper.send_metrics(to: api_url, api_token: token, use_gzip: true) + + expect(code).to eq(201) + expect(stub).to have_been_made.once + expect do + last_received_body = Zlib.gunzip(last_received_body) + end.not_to raise_error + expect(last_received_body).to eq(expected_data) + end + end + end +end diff --git a/spec/ios_send_app_size_metrics_spec.rb b/spec/ios_send_app_size_metrics_spec.rb new file mode 100644 index 000000000..f433465e1 --- /dev/null +++ b/spec/ios_send_app_size_metrics_spec.rb @@ -0,0 +1,102 @@ +require_relative './spec_helper' + +describe Fastlane::Actions::IosSendAppSizeMetricsAction do + let(:test_data_dir) { File.join(File.dirname(__FILE__), 'test-data', 'app_size_metrics') } + let(:fake_ipa_size) { 1337 } # The value used in the `app-thinning.plist` and `ios-metrics-payload.json` fixtures + + def test_app_size_action(fake_ipa_size:, expected_payload:, **other_action_args) + in_tmp_dir do |tmp_dir| + # Arrange + output_file = File.join(tmp_dir, 'output-payload') + ipa_path = File.join(tmp_dir, 'fake.ipa') + File.write(ipa_path, '-fake-ipa-file-') + allow(File).to receive(:size).with(ipa_path).and_return(fake_ipa_size) + + # Act + code = run_described_fastlane_action( + api_url: File.join('file://localhost/', output_file), + ipa_path: ipa_path, + **other_action_args + ) + + # Asserts + expect(code).to eq(201) + expect(File).to exist(output_file) + gzip_disabled = other_action_args[:use_gzip_content_encoding] == false + generated_payload = gzip_disabled ? File.read(output_file) : Zlib::GzipReader.open(output_file, &:read) + # Compare the payloads as pretty-formatted JSON, to make the diff in test failures more readable if one happen + expect(JSON.pretty_generate(JSON.parse(generated_payload))).to eq(JSON.pretty_generate(expected_payload)), 'Decompressed JSON payload was not as expected' + # Compare the payloads as raw uncompressed data as a final check + expect(generated_payload).to eq(expected_payload.to_json) + end + end + + context 'when only providing an `.ipa` file with no `app-thinning.plist` file' do + it 'generates the expected payload, compressed by default' do + expected = { + meta: [ + { name: 'Platform', value: 'iOS' }, + { name: 'App Name', value: 'my-app' }, + { name: 'App Version', value: '1.2.3' }, + { name: 'Build Type', value: 'beta' }, + { name: 'Source', value: 'unit-test' }, + ], + metrics: [ + { name: 'File Size', value: 123_456 }, + ] + } + + test_app_size_action( + fake_ipa_size: 123_456, + expected_payload: expected, + app_name: 'my-app', + build_type: 'beta', + app_version: '1.2.3', + source: 'unit-test' + ) + end + + it 'generates the expected payload, uncompressed when disabling gzip' do + expected = { + meta: [ + { name: 'Platform', value: 'iOS' }, + { name: 'App Name', value: 'my-app' }, + { name: 'App Version', value: '1.2.3' }, + { name: 'Build Type', value: 'beta' }, + { name: 'Source', value: 'unit-test' }, + ], + metrics: [ + { name: 'File Size', value: 123_456 }, + ] + } + + test_app_size_action( + fake_ipa_size: 123_456, + expected_payload: expected, + app_name: 'my-app', + build_type: 'beta', + app_version: '1.2.3', + source: 'unit-test', + use_gzip_content_encoding: false + ) + end + end + + context 'when using both an `.ipa` file and an existing `app-thinning.plist` file' do + it 'generates the expected payload containing both the Universal and optimized thinned sizes' do + app_thinning_plist_path = File.join(test_data_dir, 'app-thinning.plist') + expected_fixture = File.join(test_data_dir, 'ios-metrics-payload.json') + expected = JSON.parse(File.read(expected_fixture)) + + test_app_size_action( + fake_ipa_size: fake_ipa_size, + expected_payload: expected, + app_thinning_plist_path: app_thinning_plist_path, + app_name: 'wordpress', + build_type: 'internal', + app_version: '19.8.0.2', + source: 'unit-test' + ) + end + end +end diff --git a/spec/test-data/app_size_metrics/android-metrics-payload.json b/spec/test-data/app_size_metrics/android-metrics-payload.json new file mode 100644 index 000000000..f77014b5f --- /dev/null +++ b/spec/test-data/app_size_metrics/android-metrics-payload.json @@ -0,0 +1,26 @@ +{ + "meta": [ + { "name": "Platform", "value": "Android" }, + { "name": "App Name", "value": "wordpress" }, + { "name": "App Version", "value": "19.8-rc-3" }, + { "name": "Version Code", "value": 1214 }, + { "name": "Product Flavor", "value": "Vanilla" }, + { "name": "Build Type", "value": "Release" }, + { "name": "Source", "value": "unit-test" } + ], + "metrics": [ + { "name": "AAB File Size", "value": 987654321 }, + { "name": "APK File Size", "value": 164082, "meta": [{ "name": "split", "value": "base-arm64_v8a_2" }] }, + { "name": "Download Size", "value": 64082, "meta": [{ "name": "split", "value": "base-arm64_v8a_2" }] }, + { "name": "APK File Size", "value": 150072, "meta": [{ "name": "split", "value": "base-armeabi_v7a_2" }] }, + { "name": "Download Size", "value": 50072, "meta": [{ "name": "split", "value": "base-armeabi_v7a_2" }] }, + { "name": "APK File Size", "value": 150002, "meta": [{ "name": "split", "value": "base-armeabi_2" }] }, + { "name": "Download Size", "value": 50002, "meta": [{ "name": "split", "value": "base-armeabi_2" }] }, + { "name": "APK File Size", "value": 164080, "meta": [{ "name": "split", "value": "base-arm64_v8a" }] }, + { "name": "Download Size", "value": 64080, "meta": [{ "name": "split", "value": "base-arm64_v8a" }] }, + { "name": "APK File Size", "value": 150000, "meta": [{ "name": "split", "value": "base-armeabi" }] }, + { "name": "Download Size", "value": 50000, "meta": [{ "name": "split", "value": "base-armeabi" }] }, + { "name": "APK File Size", "value": 150070, "meta": [{ "name": "split", "value": "base-armeabi_v7a" }] }, + { "name": "Download Size", "value": 50070, "meta": [{ "name": "split", "value": "base-armeabi_v7a" }] } + ] +} diff --git a/spec/test-data/app_size_metrics/app-thinning.plist b/spec/test-data/app_size_metrics/app-thinning.plist new file mode 100644 index 000000000..a3ba80e73 --- /dev/null +++ b/spec/test-data/app_size_metrics/app-thinning.plist @@ -0,0 +1,1686 @@ + + + + + variants + + Apps/WordPress-0F68C443-4038-4AED-BDD3-9EA10588AC99.ipa + + limitUncompressedInitialPrefetchedODR + 2147483648 + onDemandResourcesAssetPacks + + sizeCompressedApp + 73174415 + sizeCompressedAppAndODR + 73174415 + sizeCompressedODR + 0 + sizeUncompressedApp + 164397537 + sizeUncompressedAppAndODR + 164397537 + sizeUncompressedInitialPrefetchedODR + 0 + sizeUncompressedInitialPrefetchedODRExceedsLimit + + sizeUncompressedODR + 0 + tagsUncompressedInitialPrefetchedODR + + variantDescriptors + + + device + iPhone11,8 + os-version + 15.0 + + + device + iPhone12,1 + os-version + 15.0 + + + + Apps/WordPress-328AA1BD-36C1-474F-8974-30E9CA61BAAF.ipa + + limitUncompressedInitialPrefetchedODR + 2147483648 + onDemandResourcesAssetPacks + + sizeCompressedApp + 80810992 + sizeCompressedAppAndODR + 80810992 + sizeCompressedODR + 0 + sizeUncompressedApp + 172226929 + sizeUncompressedAppAndODR + 172226929 + sizeUncompressedInitialPrefetchedODR + 0 + sizeUncompressedInitialPrefetchedODRExceedsLimit + + sizeUncompressedODR + 0 + tagsUncompressedInitialPrefetchedODR + + variantDescriptors + + + device + iPhone14,5 + os-version + 15.0 + + + device + iPhone13,2 + os-version + 15.0 + + + device + iPhone13,3 + os-version + 15.0 + + + device + iPhone13,1 + os-version + 15.0 + + + device + iPhone13,4 + os-version + 15.0 + + + device + iPhone14,2 + os-version + 15.0 + + + device + iPhone12,3 + os-version + 15.0 + + + device + iPhone10,3 + os-version + 15.0 + + + device + iPhone11,4 + os-version + 15.0 + + + device + iPhone14,4 + os-version + 15.0 + + + device + iPhone11,6 + os-version + 15.0 + + + device + iPhone12,5 + os-version + 15.0 + + + device + iPhone10,2 + os-version + 15.0 + + + device + iPhone10,5 + os-version + 15.0 + + + device + iPhone14,3 + os-version + 15.0 + + + device + iPhone11,2 + os-version + 15.0 + + + device + iPhone10,6 + os-version + 15.0 + + + device + iPhone9,2 + os-version + 15.0 + + + device + iPhone9,4 + os-version + 15.0 + + + + Apps/WordPress-3794860D-098D-4F74-B660-6FF02FDD13E0.ipa + + limitUncompressedInitialPrefetchedODR + 2147483648 + onDemandResourcesAssetPacks + + sizeCompressedApp + 73223402 + sizeCompressedAppAndODR + 73223402 + sizeCompressedODR + 0 + sizeUncompressedApp + 164449045 + sizeUncompressedAppAndODR + 164449045 + sizeUncompressedInitialPrefetchedODR + 0 + sizeUncompressedInitialPrefetchedODRExceedsLimit + + sizeUncompressedODR + 0 + tagsUncompressedInitialPrefetchedODR + + variantDescriptors + + + device + iPad5,1 + os-version + 15.0 + + + device + iPad7,11 + os-version + 15.0 + + + device + iPad6,12 + os-version + 15.0 + + + device + iPad5,4 + os-version + 15.0 + + + device + iPad6,8 + os-version + 15.0 + + + device + iPad6,11 + os-version + 15.0 + + + device + iPad7,5 + os-version + 15.0 + + + device + iPad7,6 + os-version + 15.0 + + + device + iPad12,2 + os-version + 15.0 + + + device + iPad7,12 + os-version + 15.0 + + + device + iPad5,3 + os-version + 15.0 + + + device + iPad11,6 + os-version + 15.0 + + + device + iPad12,1 + os-version + 15.0 + + + device + iPad6,7 + os-version + 15.0 + + + device + iPad11,7 + os-version + 15.0 + + + device + iPad5,2 + os-version + 15.0 + + + + Apps/WordPress-37DB2251-6089-4171-9B36-60F44E24D78C.ipa + + limitUncompressedInitialPrefetchedODR + 2147483648 + onDemandResourcesAssetPacks + + sizeCompressedApp + 73165631 + sizeCompressedAppAndODR + 73165631 + sizeCompressedODR + 0 + sizeUncompressedApp + 164387854 + sizeUncompressedAppAndODR + 164387854 + sizeUncompressedInitialPrefetchedODR + 0 + sizeUncompressedInitialPrefetchedODRExceedsLimit + + sizeUncompressedODR + 0 + tagsUncompressedInitialPrefetchedODR + + variantDescriptors + + + device + iPod9,1 + os-version + 15.0 + + + device + iPhone8,4 + os-version + 15.0 + + + device + iPhone8,1 + os-version + 15.0 + + + + Apps/WordPress-3B92F02C-3F0A-4F4F-BA8A-30E54AE89DCD.ipa + + limitUncompressedInitialPrefetchedODR + 2147483648 + onDemandResourcesAssetPacks + + sizeCompressedApp + 73346331 + sizeCompressedAppAndODR + 73346331 + sizeCompressedODR + 0 + sizeUncompressedApp + 164840713 + sizeUncompressedAppAndODR + 164840713 + sizeUncompressedInitialPrefetchedODR + 0 + sizeUncompressedInitialPrefetchedODRExceedsLimit + + sizeUncompressedODR + 0 + tagsUncompressedInitialPrefetchedODR + + variantDescriptors + + + device + iPad7,5 + os-version + 14.0 + + + device + iPad7,11 + os-version + 13.0 + + + device + iPad5,2 + os-version + 13.0 + + + device + iPad7,12 + os-version + 13.0 + + + device + iPad6,8 + os-version + 13.0 + + + device + iPad7,6 + os-version + 14.0 + + + device + iPad5,1 + os-version + 13.0 + + + device + iPad5,4 + os-version + 14.0 + + + device + iPad6,11 + os-version + 14.0 + + + device + iPad7,5 + os-version + 13.0 + + + device + iPad6,8 + os-version + 14.0 + + + device + iPad11,7 + os-version + 14.0 + + + device + iPad5,3 + os-version + 14.0 + + + device + iPad5,1 + os-version + 14.0 + + + device + iPad7,6 + os-version + 13.0 + + + device + iPad7,11 + os-version + 14.0 + + + device + iPad6,7 + os-version + 14.0 + + + device + iPad7,12 + os-version + 14.0 + + + device + iPad6,11 + os-version + 13.0 + + + device + iPad6,12 + os-version + 14.0 + + + device + iPad6,7 + os-version + 13.0 + + + device + iPad5,3 + os-version + 13.0 + + + device + iPad11,6 + os-version + 14.0 + + + device + iPad6,12 + os-version + 13.0 + + + device + iPad5,4 + os-version + 13.0 + + + device + iPad5,2 + os-version + 14.0 + + + + Apps/WordPress-47153C09-1B8C-4F22-910F-ED9BAAA9C32F.ipa + + limitUncompressedInitialPrefetchedODR + 2147483648 + onDemandResourcesAssetPacks + + sizeCompressedApp + 73107750 + sizeCompressedAppAndODR + 73107750 + sizeCompressedODR + 0 + sizeUncompressedApp + 164330181 + sizeUncompressedAppAndODR + 164330181 + sizeUncompressedInitialPrefetchedODR + 0 + sizeUncompressedInitialPrefetchedODRExceedsLimit + + sizeUncompressedODR + 0 + tagsUncompressedInitialPrefetchedODR + + variantDescriptors + + + device + iPhone12,8 + os-version + 15.0 + + + device + iPhone9,3 + os-version + 15.0 + + + device + iPhone10,1 + os-version + 15.0 + + + device + iPhone10,4 + os-version + 15.0 + + + device + iPhone9,1 + os-version + 15.0 + + + + Apps/WordPress-70B6F7AE-03BC-4155-9C0E-50A66EF09788.ipa + + limitUncompressedInitialPrefetchedODR + 2147483648 + onDemandResourcesAssetPacks + + sizeCompressedApp + 73165642 + sizeCompressedAppAndODR + 73165642 + sizeCompressedODR + 0 + sizeUncompressedApp + 164391941 + sizeUncompressedAppAndODR + 164391941 + sizeUncompressedInitialPrefetchedODR + 0 + sizeUncompressedInitialPrefetchedODRExceedsLimit + + sizeUncompressedODR + 0 + tagsUncompressedInitialPrefetchedODR + + variantDescriptors + + + device + iPad13,1 + os-version + 15.0 + + + device + iPad14,2 + os-version + 15.0 + + + device + iPad13,2 + os-version + 15.0 + + + device + iPad8,6 + os-version + 15.0 + + + device + iPad13,7 + os-version + 15.0 + + + device + iPad8,11 + os-version + 15.0 + + + device + iPad8,1 + os-version + 15.0 + + + device + iPad8,4 + os-version + 15.0 + + + device + iPad13,11 + os-version + 15.0 + + + device + iPad13,10 + os-version + 15.0 + + + device + iPad11,1 + os-version + 15.0 + + + device + iPad11,3 + os-version + 15.0 + + + device + iPad13,6 + os-version + 15.0 + + + device + iPad8,3 + os-version + 15.0 + + + device + iPad7,1 + os-version + 15.0 + + + device + iPad8,7 + os-version + 15.0 + + + device + iPad13,5 + os-version + 15.0 + + + device + iPad11,2 + os-version + 15.0 + + + device + iPad7,4 + os-version + 15.0 + + + device + iPad8,8 + os-version + 15.0 + + + device + iPad7,2 + os-version + 15.0 + + + device + iPad14,1 + os-version + 15.0 + + + device + iPad6,4 + os-version + 15.0 + + + device + iPad8,10 + os-version + 15.0 + + + device + iPad8,9 + os-version + 15.0 + + + device + iPad13,4 + os-version + 15.0 + + + device + iPad7,3 + os-version + 15.0 + + + device + iPad11,4 + os-version + 15.0 + + + device + iPad8,12 + os-version + 15.0 + + + device + iPad13,9 + os-version + 15.0 + + + device + iPad6,3 + os-version + 15.0 + + + device + iPad8,2 + os-version + 15.0 + + + device + MacFamily20,1 + os-version + 15.0 + + + device + iPad8,5 + os-version + 15.0 + + + device + iPad13,8 + os-version + 15.0 + + + + Apps/WordPress-95371D74-4783-480D-8A7E-EE15661E5B8D.ipa + + limitUncompressedInitialPrefetchedODR + 2147483648 + onDemandResourcesAssetPacks + + sizeCompressedApp + 73288679 + sizeCompressedAppAndODR + 73288679 + sizeCompressedODR + 0 + sizeUncompressedApp + 164779586 + sizeUncompressedAppAndODR + 164779586 + sizeUncompressedInitialPrefetchedODR + 0 + sizeUncompressedInitialPrefetchedODRExceedsLimit + + sizeUncompressedODR + 0 + tagsUncompressedInitialPrefetchedODR + + variantDescriptors + + + device + iPod9,1 + os-version + 14.0 + + + device + iPhone8,4 + os-version + 14.0 + + + device + iPhone8,1 + os-version + 13.0 + + + device + iPhone8,4 + os-version + 13.0 + + + device + iPod9,1 + os-version + 13.0 + + + device + iPhone8,1 + os-version + 14.0 + + + + Apps/WordPress-9CD32B95-A5D1-4274-839C-640FDAD77B26.ipa + + limitUncompressedInitialPrefetchedODR + 2147483648 + onDemandResourcesAssetPacks + + sizeCompressedApp + 73230799 + sizeCompressedAppAndODR + 73230799 + sizeCompressedODR + 0 + sizeUncompressedApp + 164721913 + sizeUncompressedAppAndODR + 164721913 + sizeUncompressedInitialPrefetchedODR + 0 + sizeUncompressedInitialPrefetchedODRExceedsLimit + + sizeUncompressedODR + 0 + tagsUncompressedInitialPrefetchedODR + + variantDescriptors + + + device + iPhone9,3 + os-version + 13.0 + + + device + iPhone9,3 + os-version + 14.0 + + + device + iPhone10,1 + os-version + 14.0 + + + device + iPhone10,1 + os-version + 13.0 + + + device + iPhone9,1 + os-version + 14.0 + + + device + iPhone10,4 + os-version + 14.0 + + + device + iPhone12,8 + os-version + 14.0 + + + device + iPhone10,4 + os-version + 13.0 + + + device + iPhone12,8 + os-version + 13.0 + + + device + iPhone9,1 + os-version + 13.0 + + + + Apps/WordPress-B1AFCDA3-9593-42C4-ACE5-FD91583FD214.ipa + + limitUncompressedInitialPrefetchedODR + 2147483648 + onDemandResourcesAssetPacks + + sizeCompressedApp + 73288723 + sizeCompressedAppAndODR + 73288723 + sizeCompressedODR + 0 + sizeUncompressedApp + 164783609 + sizeUncompressedAppAndODR + 164783609 + sizeUncompressedInitialPrefetchedODR + 0 + sizeUncompressedInitialPrefetchedODRExceedsLimit + + sizeUncompressedODR + 0 + tagsUncompressedInitialPrefetchedODR + + variantDescriptors + + + device + iPad6,4 + os-version + 14.0 + + + device + iPad6,3 + os-version + 13.0 + + + device + iPad7,2 + os-version + 14.0 + + + device + iPad8,1 + os-version + 13.0 + + + device + iPad13,7 + os-version + 14.0 + + + device + iPad8,11 + os-version + 14.0 + + + device + iPad8,6 + os-version + 13.0 + + + device + iPad13,11 + os-version + 14.0 + + + device + iPad8,1 + os-version + 14.0 + + + device + iPad13,4 + os-version + 14.0 + + + device + iPad8,10 + os-version + 13.0 + + + device + iPad7,3 + os-version + 14.0 + + + device + iPad13,8 + os-version + 14.0 + + + device + iPad11,4 + os-version + 14.0 + + + device + iPad6,4 + os-version + 13.0 + + + device + iPad8,7 + os-version + 14.0 + + + device + iPad8,4 + os-version + 13.0 + + + device + iPad7,1 + os-version + 14.0 + + + device + iPad8,4 + os-version + 14.0 + + + device + iPad7,2 + os-version + 13.0 + + + device + iPad13,1 + os-version + 14.0 + + + device + iPad11,2 + os-version + 14.0 + + + device + iPad8,12 + os-version + 13.0 + + + device + iPad8,6 + os-version + 14.0 + + + device + iPad8,8 + os-version + 13.0 + + + device + iPad8,2 + os-version + 14.0 + + + device + iPad8,11 + os-version + 13.0 + + + device + iPad13,10 + os-version + 14.0 + + + device + iPad11,3 + os-version + 13.0 + + + device + iPad8,8 + os-version + 14.0 + + + device + iPad11,2 + os-version + 13.0 + + + device + iPad8,12 + os-version + 14.0 + + + device + iPad13,9 + os-version + 14.0 + + + device + iPad7,3 + os-version + 13.0 + + + device + iPad13,2 + os-version + 14.0 + + + device + iPad13,5 + os-version + 14.0 + + + device + MacFamily20,1 + os-version + 14.0 + + + device + iPad11,1 + os-version + 14.0 + + + device + iPad8,2 + os-version + 13.0 + + + device + iPad6,3 + os-version + 14.0 + + + device + iPad7,4 + os-version + 13.0 + + + device + iPad13,6 + os-version + 14.0 + + + device + iPad8,9 + os-version + 13.0 + + + device + iPad8,3 + os-version + 14.0 + + + device + iPad8,7 + os-version + 13.0 + + + device + iPad8,5 + os-version + 13.0 + + + device + iPad11,1 + os-version + 13.0 + + + device + iPad8,5 + os-version + 14.0 + + + device + iPad11,3 + os-version + 14.0 + + + device + iPad8,9 + os-version + 14.0 + + + device + iPad7,4 + os-version + 14.0 + + + device + iPad7,1 + os-version + 13.0 + + + device + iPad8,10 + os-version + 14.0 + + + device + iPad11,4 + os-version + 13.0 + + + device + iPad8,3 + os-version + 13.0 + + + + Apps/WordPress-D6E80112-8444-447A-AAC1-810118FA1875.ipa + + limitUncompressedInitialPrefetchedODR + 2147483648 + onDemandResourcesAssetPacks + + sizeCompressedApp + 80933891 + sizeCompressedAppAndODR + 80933891 + sizeCompressedODR + 0 + sizeUncompressedApp + 172618525 + sizeUncompressedAppAndODR + 172618525 + sizeUncompressedInitialPrefetchedODR + 0 + sizeUncompressedInitialPrefetchedODRExceedsLimit + + sizeUncompressedODR + 0 + tagsUncompressedInitialPrefetchedODR + + variantDescriptors + + + device + iPhone12,5 + os-version + 13.0 + + + device + iPhone10,6 + os-version + 14.0 + + + device + iPhone12,3 + os-version + 14.0 + + + device + iPhone10,3 + os-version + 14.0 + + + device + iPhone13,3 + os-version + 14.0 + + + device + iPhone10,5 + os-version + 14.0 + + + device + iPhone11,6 + os-version + 13.0 + + + device + iPhone11,2 + os-version + 13.0 + + + device + iPhone13,4 + os-version + 14.0 + + + device + iPhone9,4 + os-version + 13.0 + + + device + iPhone10,2 + os-version + 14.0 + + + device + iPhone11,4 + os-version + 13.0 + + + device + iPhone10,3 + os-version + 13.0 + + + device + iPhone12,5 + os-version + 14.0 + + + device + iPhone10,2 + os-version + 13.0 + + + device + iPhone10,6 + os-version + 13.0 + + + device + iPhone10,5 + os-version + 13.0 + + + device + iPhone11,4 + os-version + 14.0 + + + device + iPhone11,6 + os-version + 14.0 + + + device + iPhone9,4 + os-version + 14.0 + + + device + iPhone11,2 + os-version + 14.0 + + + device + iPhone9,2 + os-version + 14.0 + + + device + iPhone9,2 + os-version + 13.0 + + + device + iPhone12,3 + os-version + 13.0 + + + device + iPhone13,2 + os-version + 14.0 + + + device + iPhone13,1 + os-version + 14.0 + + + + Apps/WordPress-E8A051CA-A279-4725-B18B-763A1E4E1FB7.ipa + + limitUncompressedInitialPrefetchedODR + 2147483648 + onDemandResourcesAssetPacks + + sizeCompressedApp + 81097487 + sizeCompressedAppAndODR + 81097487 + sizeCompressedODR + 0 + sizeUncompressedApp + 172781682 + sizeUncompressedAppAndODR + 172781682 + sizeUncompressedInitialPrefetchedODR + 0 + sizeUncompressedInitialPrefetchedODRExceedsLimit + + sizeUncompressedODR + 0 + tagsUncompressedInitialPrefetchedODR + + variantDescriptors + + + device + iPhone8,2 + os-version + 13.0 + + + device + iPhone8,2 + os-version + 14.0 + + + + Apps/WordPress-FB103AD6-CD63-43CE-B47B-19C29CB669BA.ipa + + limitUncompressedInitialPrefetchedODR + 2147483648 + onDemandResourcesAssetPacks + + sizeCompressedApp + 73297518 + sizeCompressedAppAndODR + 73297518 + sizeCompressedODR + 0 + sizeUncompressedApp + 164789269 + sizeUncompressedAppAndODR + 164789269 + sizeUncompressedInitialPrefetchedODR + 0 + sizeUncompressedInitialPrefetchedODRExceedsLimit + + sizeUncompressedODR + 0 + tagsUncompressedInitialPrefetchedODR + + variantDescriptors + + + device + iPhone12,1 + os-version + 13.0 + + + device + iPhone12,1 + os-version + 14.0 + + + device + iPhone11,8 + os-version + 14.0 + + + device + iPhone11,8 + os-version + 13.0 + + + + Apps/WordPress-FD1D21DD-4330-4020-A153-8CE54A9908D2.ipa + + limitUncompressedInitialPrefetchedODR + 2147483648 + onDemandResourcesAssetPacks + + sizeCompressedApp + 80974447 + sizeCompressedAppAndODR + 80974447 + sizeCompressedODR + 0 + sizeUncompressedApp + 172389950 + sizeUncompressedAppAndODR + 172389950 + sizeUncompressedInitialPrefetchedODR + 0 + sizeUncompressedInitialPrefetchedODRExceedsLimit + + sizeUncompressedODR + 0 + tagsUncompressedInitialPrefetchedODR + + variantDescriptors + + + device + iPhone8,2 + os-version + 15.0 + + + + Apps/WordPress.ipa + + limitUncompressedInitialPrefetchedODR + 2147483648 + onDemandResourcesAssetPacks + + sizeCompressedApp + 98758624 + sizeCompressedAppAndODR + 98758624 + sizeCompressedODR + 0 + sizeUncompressedApp + 195563137 + sizeUncompressedAppAndODR + 195563137 + sizeUncompressedInitialPrefetchedODR + 0 + sizeUncompressedInitialPrefetchedODRExceedsLimit + + sizeUncompressedODR + 0 + tagsUncompressedInitialPrefetchedODR + + + + + diff --git a/spec/test-data/app_size_metrics/ios-metrics-payload.json b/spec/test-data/app_size_metrics/ios-metrics-payload.json new file mode 100644 index 000000000..7a0b46366 --- /dev/null +++ b/spec/test-data/app_size_metrics/ios-metrics-payload.json @@ -0,0 +1,434 @@ +{ + "meta": [ + { "name": "Platform", "value": "iOS" }, + { "name": "App Name", "value": "wordpress" }, + { "name": "App Version", "value": "19.8.0.2" }, + { "name": "Build Type", "value": "internal" }, + { "name": "Source", "value": "unit-test" } + ], + "metrics": [ + { "name": "File Size", "value": 1337 }, + { "name": "Download Size", "value": 73174415, "meta": [{ "name": "device", "value": "iPhone11,8" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164397537, "meta": [{ "name": "device", "value": "iPhone11,8" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73174415, "meta": [{ "name": "device", "value": "iPhone12,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164397537, "meta": [{ "name": "device", "value": "iPhone12,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 80810992, "meta": [{ "name": "device", "value": "iPhone14,5" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 172226929, "meta": [{ "name": "device", "value": "iPhone14,5" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 80810992, "meta": [{ "name": "device", "value": "iPhone13,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 172226929, "meta": [{ "name": "device", "value": "iPhone13,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 80810992, "meta": [{ "name": "device", "value": "iPhone13,3" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 172226929, "meta": [{ "name": "device", "value": "iPhone13,3" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 80810992, "meta": [{ "name": "device", "value": "iPhone13,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 172226929, "meta": [{ "name": "device", "value": "iPhone13,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 80810992, "meta": [{ "name": "device", "value": "iPhone13,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 172226929, "meta": [{ "name": "device", "value": "iPhone13,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 80810992, "meta": [{ "name": "device", "value": "iPhone14,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 172226929, "meta": [{ "name": "device", "value": "iPhone14,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 80810992, "meta": [{ "name": "device", "value": "iPhone12,3" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 172226929, "meta": [{ "name": "device", "value": "iPhone12,3" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 80810992, "meta": [{ "name": "device", "value": "iPhone10,3" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 172226929, "meta": [{ "name": "device", "value": "iPhone10,3" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 80810992, "meta": [{ "name": "device", "value": "iPhone11,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 172226929, "meta": [{ "name": "device", "value": "iPhone11,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 80810992, "meta": [{ "name": "device", "value": "iPhone14,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 172226929, "meta": [{ "name": "device", "value": "iPhone14,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 80810992, "meta": [{ "name": "device", "value": "iPhone11,6" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 172226929, "meta": [{ "name": "device", "value": "iPhone11,6" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 80810992, "meta": [{ "name": "device", "value": "iPhone12,5" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 172226929, "meta": [{ "name": "device", "value": "iPhone12,5" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 80810992, "meta": [{ "name": "device", "value": "iPhone10,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 172226929, "meta": [{ "name": "device", "value": "iPhone10,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 80810992, "meta": [{ "name": "device", "value": "iPhone10,5" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 172226929, "meta": [{ "name": "device", "value": "iPhone10,5" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 80810992, "meta": [{ "name": "device", "value": "iPhone14,3" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 172226929, "meta": [{ "name": "device", "value": "iPhone14,3" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 80810992, "meta": [{ "name": "device", "value": "iPhone11,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 172226929, "meta": [{ "name": "device", "value": "iPhone11,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 80810992, "meta": [{ "name": "device", "value": "iPhone10,6" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 172226929, "meta": [{ "name": "device", "value": "iPhone10,6" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 80810992, "meta": [{ "name": "device", "value": "iPhone9,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 172226929, "meta": [{ "name": "device", "value": "iPhone9,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 80810992, "meta": [{ "name": "device", "value": "iPhone9,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 172226929, "meta": [{ "name": "device", "value": "iPhone9,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73223402, "meta": [{ "name": "device", "value": "iPad5,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164449045, "meta": [{ "name": "device", "value": "iPad5,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73223402, "meta": [{ "name": "device", "value": "iPad7,11" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164449045, "meta": [{ "name": "device", "value": "iPad7,11" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73223402, "meta": [{ "name": "device", "value": "iPad6,12" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164449045, "meta": [{ "name": "device", "value": "iPad6,12" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73223402, "meta": [{ "name": "device", "value": "iPad5,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164449045, "meta": [{ "name": "device", "value": "iPad5,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73223402, "meta": [{ "name": "device", "value": "iPad6,8" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164449045, "meta": [{ "name": "device", "value": "iPad6,8" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73223402, "meta": [{ "name": "device", "value": "iPad6,11" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164449045, "meta": [{ "name": "device", "value": "iPad6,11" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73223402, "meta": [{ "name": "device", "value": "iPad7,5" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164449045, "meta": [{ "name": "device", "value": "iPad7,5" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73223402, "meta": [{ "name": "device", "value": "iPad7,6" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164449045, "meta": [{ "name": "device", "value": "iPad7,6" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73223402, "meta": [{ "name": "device", "value": "iPad12,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164449045, "meta": [{ "name": "device", "value": "iPad12,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73223402, "meta": [{ "name": "device", "value": "iPad7,12" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164449045, "meta": [{ "name": "device", "value": "iPad7,12" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73223402, "meta": [{ "name": "device", "value": "iPad5,3" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164449045, "meta": [{ "name": "device", "value": "iPad5,3" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73223402, "meta": [{ "name": "device", "value": "iPad11,6" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164449045, "meta": [{ "name": "device", "value": "iPad11,6" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73223402, "meta": [{ "name": "device", "value": "iPad12,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164449045, "meta": [{ "name": "device", "value": "iPad12,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73223402, "meta": [{ "name": "device", "value": "iPad6,7" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164449045, "meta": [{ "name": "device", "value": "iPad6,7" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73223402, "meta": [{ "name": "device", "value": "iPad11,7" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164449045, "meta": [{ "name": "device", "value": "iPad11,7" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73223402, "meta": [{ "name": "device", "value": "iPad5,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164449045, "meta": [{ "name": "device", "value": "iPad5,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165631, "meta": [{ "name": "device", "value": "iPod9,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164387854, "meta": [{ "name": "device", "value": "iPod9,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165631, "meta": [{ "name": "device", "value": "iPhone8,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164387854, "meta": [{ "name": "device", "value": "iPhone8,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165631, "meta": [{ "name": "device", "value": "iPhone8,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164387854, "meta": [{ "name": "device", "value": "iPhone8,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad7,5" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad7,5" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad7,11" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad7,11" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad5,2" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad5,2" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad7,12" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad7,12" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad6,8" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad6,8" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad7,6" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad7,6" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad5,1" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad5,1" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad5,4" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad5,4" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad6,11" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad6,11" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad7,5" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad7,5" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad6,8" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad6,8" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad11,7" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad11,7" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad5,3" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad5,3" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad5,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad5,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad7,6" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad7,6" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad7,11" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad7,11" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad6,7" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad6,7" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad7,12" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad7,12" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad6,11" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad6,11" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad6,12" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad6,12" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad6,7" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad6,7" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad5,3" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad5,3" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad11,6" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad11,6" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad6,12" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad6,12" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad5,4" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad5,4" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73346331, "meta": [{ "name": "device", "value": "iPad5,2" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164840713, "meta": [{ "name": "device", "value": "iPad5,2" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73107750, "meta": [{ "name": "device", "value": "iPhone12,8" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164330181, "meta": [{ "name": "device", "value": "iPhone12,8" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73107750, "meta": [{ "name": "device", "value": "iPhone9,3" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164330181, "meta": [{ "name": "device", "value": "iPhone9,3" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73107750, "meta": [{ "name": "device", "value": "iPhone10,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164330181, "meta": [{ "name": "device", "value": "iPhone10,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73107750, "meta": [{ "name": "device", "value": "iPhone10,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164330181, "meta": [{ "name": "device", "value": "iPhone10,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73107750, "meta": [{ "name": "device", "value": "iPhone9,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164330181, "meta": [{ "name": "device", "value": "iPhone9,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad13,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad13,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad14,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad14,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad13,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad13,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad8,6" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad8,6" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad13,7" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad13,7" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad8,11" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad8,11" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad8,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad8,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad8,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad8,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad13,11" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad13,11" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad13,10" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad13,10" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad11,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad11,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad11,3" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad11,3" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad13,6" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad13,6" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad8,3" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad8,3" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad7,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad7,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad8,7" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad8,7" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad13,5" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad13,5" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad11,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad11,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad7,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad7,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad8,8" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad8,8" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad7,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad7,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad14,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad14,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad6,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad6,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad8,10" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad8,10" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad8,9" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad8,9" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad13,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad13,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad7,3" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad7,3" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad11,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad11,4" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad8,12" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad8,12" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad13,9" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad13,9" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad6,3" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad6,3" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad8,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad8,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "MacFamily20,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "MacFamily20,1" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad8,5" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad8,5" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73165642, "meta": [{ "name": "device", "value": "iPad13,8" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 164391941, "meta": [{ "name": "device", "value": "iPad13,8" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 73288679, "meta": [{ "name": "device", "value": "iPod9,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164779586, "meta": [{ "name": "device", "value": "iPod9,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288679, "meta": [{ "name": "device", "value": "iPhone8,4" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164779586, "meta": [{ "name": "device", "value": "iPhone8,4" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288679, "meta": [{ "name": "device", "value": "iPhone8,1" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164779586, "meta": [{ "name": "device", "value": "iPhone8,1" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288679, "meta": [{ "name": "device", "value": "iPhone8,4" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164779586, "meta": [{ "name": "device", "value": "iPhone8,4" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288679, "meta": [{ "name": "device", "value": "iPod9,1" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164779586, "meta": [{ "name": "device", "value": "iPod9,1" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288679, "meta": [{ "name": "device", "value": "iPhone8,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164779586, "meta": [{ "name": "device", "value": "iPhone8,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73230799, "meta": [{ "name": "device", "value": "iPhone9,3" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164721913, "meta": [{ "name": "device", "value": "iPhone9,3" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73230799, "meta": [{ "name": "device", "value": "iPhone9,3" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164721913, "meta": [{ "name": "device", "value": "iPhone9,3" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73230799, "meta": [{ "name": "device", "value": "iPhone10,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164721913, "meta": [{ "name": "device", "value": "iPhone10,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73230799, "meta": [{ "name": "device", "value": "iPhone10,1" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164721913, "meta": [{ "name": "device", "value": "iPhone10,1" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73230799, "meta": [{ "name": "device", "value": "iPhone9,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164721913, "meta": [{ "name": "device", "value": "iPhone9,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73230799, "meta": [{ "name": "device", "value": "iPhone10,4" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164721913, "meta": [{ "name": "device", "value": "iPhone10,4" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73230799, "meta": [{ "name": "device", "value": "iPhone12,8" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164721913, "meta": [{ "name": "device", "value": "iPhone12,8" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73230799, "meta": [{ "name": "device", "value": "iPhone10,4" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164721913, "meta": [{ "name": "device", "value": "iPhone10,4" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73230799, "meta": [{ "name": "device", "value": "iPhone12,8" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164721913, "meta": [{ "name": "device", "value": "iPhone12,8" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73230799, "meta": [{ "name": "device", "value": "iPhone9,1" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164721913, "meta": [{ "name": "device", "value": "iPhone9,1" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad6,4" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad6,4" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad6,3" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad6,3" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad7,2" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad7,2" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,1" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,1" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad13,7" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad13,7" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,11" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,11" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,6" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,6" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad13,11" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad13,11" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad13,4" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad13,4" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,10" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,10" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad7,3" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad7,3" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad13,8" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad13,8" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad11,4" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad11,4" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad6,4" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad6,4" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,7" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,7" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,4" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,4" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad7,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad7,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,4" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,4" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad7,2" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad7,2" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad13,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad13,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad11,2" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad11,2" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,12" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,12" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,6" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,6" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,8" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,8" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,2" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,2" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,11" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,11" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad13,10" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad13,10" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad11,3" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad11,3" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,8" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,8" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad11,2" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad11,2" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,12" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,12" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad13,9" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad13,9" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad7,3" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad7,3" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad13,2" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad13,2" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad13,5" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad13,5" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "MacFamily20,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "MacFamily20,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad11,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad11,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,2" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,2" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad6,3" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad6,3" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad7,4" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad7,4" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad13,6" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad13,6" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,9" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,9" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,3" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,3" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,7" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,7" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,5" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,5" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad11,1" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad11,1" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,5" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,5" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad11,3" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad11,3" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,9" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,9" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad7,4" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad7,4" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad7,1" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad7,1" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,10" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,10" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad11,4" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad11,4" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73288723, "meta": [{ "name": "device", "value": "iPad8,3" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164783609, "meta": [{ "name": "device", "value": "iPad8,3" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone12,5" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone12,5" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone10,6" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone10,6" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone12,3" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone12,3" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone10,3" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone10,3" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone13,3" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone13,3" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone10,5" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone10,5" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone11,6" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone11,6" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone11,2" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone11,2" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone13,4" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone13,4" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone9,4" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone9,4" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone10,2" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone10,2" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone11,4" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone11,4" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone10,3" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone10,3" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone12,5" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone12,5" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone10,2" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone10,2" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone10,6" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone10,6" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone10,5" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone10,5" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone11,4" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone11,4" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone11,6" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone11,6" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone9,4" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone9,4" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone11,2" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone11,2" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone9,2" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone9,2" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone9,2" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone9,2" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone12,3" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone12,3" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone13,2" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone13,2" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 80933891, "meta": [{ "name": "device", "value": "iPhone13,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 172618525, "meta": [{ "name": "device", "value": "iPhone13,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 81097487, "meta": [{ "name": "device", "value": "iPhone8,2" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 172781682, "meta": [{ "name": "device", "value": "iPhone8,2" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 81097487, "meta": [{ "name": "device", "value": "iPhone8,2" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 172781682, "meta": [{ "name": "device", "value": "iPhone8,2" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73297518, "meta": [{ "name": "device", "value": "iPhone12,1" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164789269, "meta": [{ "name": "device", "value": "iPhone12,1" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 73297518, "meta": [{ "name": "device", "value": "iPhone12,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164789269, "meta": [{ "name": "device", "value": "iPhone12,1" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73297518, "meta": [{ "name": "device", "value": "iPhone11,8" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Install Size", "value": 164789269, "meta": [{ "name": "device", "value": "iPhone11,8" }, { "name": "OS Version", "value": "14.0" }] }, + { "name": "Download Size", "value": 73297518, "meta": [{ "name": "device", "value": "iPhone11,8" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Install Size", "value": 164789269, "meta": [{ "name": "device", "value": "iPhone11,8" }, { "name": "OS Version", "value": "13.0" }] }, + { "name": "Download Size", "value": 80974447, "meta": [{ "name": "device", "value": "iPhone8,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Install Size", "value": 172389950, "meta": [{ "name": "device", "value": "iPhone8,2" }, { "name": "OS Version", "value": "15.0" }] }, + { "name": "Download Size", "value": 98758624, "meta": [{ "name": "device", "value": "Universal" }] }, + { "name": "Install Size", "value": 195563137, "meta": [{ "name": "device", "value": "Universal" }] } + ] +}