diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml
index 616a323..fb57921 100644
--- a/.github/workflows/flutter.yml
+++ b/.github/workflows/flutter.yml
@@ -1,37 +1,185 @@
-# This workflow uses actions that are not certified by GitHub.
-# They are provided by a third-party and are governed by
-# separate terms of service, privacy policy, and support
-# documentation.
-
-name: Dart
+name: "Flutter Testing"
on:
- push:
- branches: [ main ]
pull_request:
- branches: [ main ]
+ branches:
+ - main
+ paths-ignore:
+ - '*.md'
+ - '**/*.md'
+ push:
+ branches:
+ - main
+ tags:
+ - '*'
+ paths-ignore:
+ - '*.md'
+ - '**/*.md'
jobs:
- build:
+ # Building flutter
+ assemble:
runs-on: ubuntu-latest
-
steps:
- uses: actions/checkout@v3
- uses: subosito/flutter-action@v2
+ with:
+ flutter-version: '2.10.5'
+ channel: 'stable'
- - name: Check flutter version
- run: flutter --version
-
- - name: Get dependencies
+ - name: "Get dependencies"
run: flutter pub get
# - name: Generate icons
# run: flutter pub run flutter_launcher_icons:main
-# - name: Run unit tests
-# run: flutter test
-
-# - name: Run integration tests
-# run: flutter test integration_test
+# - name: "Check for any formatting issues in the code."
+# run: flutter format --set-exit-if-changed .
+
+# - name: "Statically analyze the Dart code for any errors."
+# run: flutter analyze .
+
+ - name: "Upload build artifacts"
+ uses: actions/upload-artifact@v3
+ with:
+ name: flutter-app
+ path: .
+
+ # Testing flutter
+ test_unit:
+ runs-on: ubuntu-latest
+ needs: assemble
+ steps:
+ - name: "Download build artifacts"
+ uses: actions/download-artifact@v3
+ with:
+ name: flutter-app
+ path: .
+
+# - name: "Run unit tests"
+# run: flutter test
+
+ # Testing Android
+ test_android:
+ runs-on: macos-latest # because of native hardware acceleration support provided by HAXM
+ needs: assemble
+ strategy:
+ matrix:
+ api-level: [ 21, 23, 29 ]
+ steps:
+ - name: "Download build artifacts"
+ uses: actions/download-artifact@v3
+ with:
+ name: flutter-app
+ path: .
+
+ - name: "Gradle cache"
+ uses: gradle/gradle-build-action@v2
+
+ - name: "AVD cache"
+ uses: actions/cache@v3
+ id: avd-cache
+ with:
+ path: |
+ ~/.android/avd/*
+ ~/.android/adb*
+ key: avd-${{ matrix.api-level }}
+
+ - name: "create AVD and generate snapshot for caching"
+ if: steps.avd-cache.outputs.cache-hit != 'true'
+ uses: reactivecircus/android-emulator-runner@v2
+ with:
+ api-level: ${{ matrix.api-level }}
+ force-avd-creation: false
+ emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
+ disable-animations: false
+ script: echo "Generated AVD snapshot for caching."
+
+ - uses: subosito/flutter-action@v2
+ with:
+ flutter-version: '2.10.5'
+ channel: 'stable'
+
+ - name: "Run integration tests (android SDK #${{ matrix.api-level }})"
+ uses: reactivecircus/android-emulator-runner@v2
+ with:
+ api-level: ${{ matrix.api-level }}
+ profile: Nexus 6
+ script: flutter test integration_test
+
+ # Testing iOS
+ test_ios:
+ runs-on: macos-latest
+ needs: assemble
+ strategy:
+ matrix:
+ device:
+ - "iPhone 8"
+ - "iPhone 11 Pro Max"
+ steps:
+ - name: "Download build artifacts"
+ uses: actions/download-artifact@v3
+ with:
+ name: flutter-app
+ path: .
+
+ - uses: maxim-lobanov/setup-xcode@v1
+ with:
+ xcode-version: latest-stable
+
+ - name: "List all simulators"
+ run: xcrun xctrace list devices
+
+ - name: "Start Simulator"
+ run: xcrun simctl boot "${{ matrix.device }}"
-# TODO: add package build
+ - uses: subosito/flutter-action@v2
+ with:
+ flutter-version: '2.10.5'
+ channel: 'stable'
+
+ - name: "Get dependencies"
+ run: flutter pub get
+
+ - name: "Run integration tests - (${{ matrix.device }})"
+ run: flutter test integration_test
+
+ # Build android package
+ build_android:
+ runs-on: ubuntu-latest
+ needs: [ test_unit, test_android, test_ios ]
+ steps:
+ - uses: subosito/flutter-action@v2
+ with:
+ flutter-version: '2.10.5'
+ channel: 'stable'
+
+ # Build ios package
+ build_ios:
+ runs-on: macos-latest
+ needs: [ test_unit, test_android, test_ios ]
+ steps:
+ - uses: subosito/flutter-action@v2
+ with:
+ flutter-version: '2.10.5'
+ channel: 'stable'
+
+ # Publish android package
+ deploy_android:
+ runs-on: ubuntu-latest
+ needs: build_android
+ steps:
+ - uses: subosito/flutter-action@v2
+ with:
+ flutter-version: '2.10.5'
+ channel: 'stable'
+
+ # Publish ios package
+ deploy_ios:
+ runs-on: macos-latest
+ needs: build_ios
+ steps:
+ - uses: subosito/flutter-action@v2
+ with:
+ flutter-version: '2.10.5'
+ channel: 'stable'
diff --git a/.github/workflows/ios_build.yml b/.github/workflows/ios_build.yml
new file mode 100644
index 0000000..0f79f38
--- /dev/null
+++ b/.github/workflows/ios_build.yml
@@ -0,0 +1,70 @@
+name: "Flutter iOS build"
+
+on:
+ push:
+ branches:
+ - main
+ - cicd-testing
+ tags:
+ - '*'
+ paths-ignore:
+ - '*.md'
+ - '**/*.md'
+
+jobs:
+ build_ios:
+ runs-on: macos-latest
+ strategy:
+ matrix:
+ device:
+ - "iPhone 11 Pro Max"
+ steps:
+ - uses: actions/checkout@v3
+ - name: Install the Apple certificate and provisioning profile
+ env:
+ BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
+ P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
+ BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }}
+ KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
+ run: |
+ # create variables
+ CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
+ PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision
+ KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
+
+ # import certificate and provisioning profile from secrets
+ echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode --output $CERTIFICATE_PATH
+ echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode --output $PP_PATH
+
+ # create temporary keychain
+ security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
+ security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
+ security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
+
+ # import certificate to keychain
+ security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
+ security list-keychain -d user -s $KEYCHAIN_PATH
+
+ # apply provisioning profile
+ mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
+ cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
+ - uses: maxim-lobanov/setup-xcode@v1
+ with:
+ xcode-version: latest-stable
+
+ - name: "List all simulators"
+ run: xcrun xctrace list devices
+
+ - name: "Start Simulator"
+ run: xcrun simctl boot "${{ matrix.device }}"
+
+ - uses: subosito/flutter-action@v2
+ with:
+ flutter-version: '2.10.5'
+ channel: 'stable'
+
+ - name: "Get dependencies"
+ run: flutter pub get
+
+ - name: "Run build - (${{ matrix.device }})"
+ run: flutter build ipa --release
diff --git a/README.md b/README.md
index 8fb00f2..9d09207 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,7 @@
# TabManager
+
+[](https://github.com/Mikopet/tab_manager/actions/workflows/flutter.yml)
+
What is `tab_manager` about?
Well, it's easy, this is a tab manager. Imagine, you have a bigger group at an event, like a camp.
diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist
index 8d4492f..1dc6cf7 100644
--- a/ios/Flutter/AppFrameworkInfo.plist
+++ b/ios/Flutter/AppFrameworkInfo.plist
@@ -21,6 +21,6 @@
CFBundleVersion
1.0
MinimumOSVersion
- 9.0
+ 13.0
diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig
index 592ceee..ec97fc6 100644
--- a/ios/Flutter/Debug.xcconfig
+++ b/ios/Flutter/Debug.xcconfig
@@ -1 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig
index 592ceee..c4855bf 100644
--- a/ios/Flutter/Release.xcconfig
+++ b/ios/Flutter/Release.xcconfig
@@ -1 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
diff --git a/ios/Podfile b/ios/Podfile
index 330220c..3829655 100644
--- a/ios/Podfile
+++ b/ios/Podfile
@@ -1 +1,44 @@
platform :ios, '13.0'
+
+ENV['COCOAPODS_DISABLE_STATS'] = 'true'
+
+project 'Runner', {
+ 'Debug' => :debug,
+ 'Profile' => :release,
+ 'Release' => :release,
+}
+
+def flutter_root
+ generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
+ unless File.exist?(generated_xcode_build_settings_path)
+ raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
+ end
+
+ File.foreach(generated_xcode_build_settings_path) do |line|
+ matches = line.match(/FLUTTER_ROOT\=(.*)/)
+ return matches[1].strip if matches
+ end
+ raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
+end
+
+require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
+
+flutter_ios_podfile_setup
+
+target 'Runner' do
+ use_frameworks!
+ use_modular_headers!
+
+ flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
+end
+
+post_install do |installer|
+ installer.pods_project.targets.each do |target|
+ flutter_additional_ios_build_settings(target)
+
+ target.build_configurations.each do |config|
+ config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
+ end
+ end
+end
+
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 91b470d..47ef7ca 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -13,6 +13,7 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
+ DE3D4F033DA3DABEA6BBD0DD /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 743E1DC107EC084FAAE9B8DC /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -32,6 +33,8 @@
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
+ 662028EB5843DFEEA39FD377 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
+ 743E1DC107EC084FAAE9B8DC /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
@@ -42,6 +45,8 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ BE6E3D594CAF80E191A2FC7F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
+ FA051DF4E00B4A9E0BF71A8B /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -49,12 +54,21 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ DE3D4F033DA3DABEA6BBD0DD /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
+ 3455FC3E3BD5DA7857FB2142 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 743E1DC107EC084FAAE9B8DC /* Pods_Runner.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
@@ -72,6 +86,8 @@
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
+ D4BB81ECB98D676B022CFB12 /* Pods */,
+ 3455FC3E3BD5DA7857FB2142 /* Frameworks */,
);
sourceTree = "";
};
@@ -98,6 +114,17 @@
path = Runner;
sourceTree = "";
};
+ D4BB81ECB98D676B022CFB12 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ BE6E3D594CAF80E191A2FC7F /* Pods-Runner.debug.xcconfig */,
+ 662028EB5843DFEEA39FD377 /* Pods-Runner.release.xcconfig */,
+ FA051DF4E00B4A9E0BF71A8B /* Pods-Runner.profile.xcconfig */,
+ );
+ name = Pods;
+ path = Pods;
+ sourceTree = "";
+ };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -105,12 +132,14 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
+ DBDD714A0337AA189CB18711 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
+ E2C23DFD321B314D9EBEFAF6 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -133,6 +162,7 @@
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
+ DevelopmentTeam = 648SCHLW8P;
};
};
};
@@ -197,6 +227,45 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
+ DBDD714A0337AA189CB18711 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ E2C23DFD321B314D9EBEFAF6 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -272,7 +341,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -349,7 +418,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -398,7 +467,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -478,4 +547,4 @@
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
-}
\ No newline at end of file
+}
diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata
index 1d526a1..21a3cc1 100644
--- a/ios/Runner.xcworkspace/contents.xcworkspacedata
+++ b/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -4,4 +4,7 @@
+
+
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 48e2905..72a985d 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -13,7 +13,7 @@
CFBundleInfoDictionaryVersion
6.0
CFBundleName
- tab_manager
+ tabmanager
CFBundlePackageType
APPL
CFBundleShortVersionString