Fetch target product-type from AppleBundleInfo

Use the AppleBundleInfo provider if it is present in order to fetch
the product type for the target in Xcode.

PiperOrigin-RevId: 185722935
diff --git a/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl b/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl
index 955e964..1c30818 100644
--- a/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl
+++ b/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl
@@ -521,9 +521,6 @@
   target_kind = rule.kind
   rule_attr = _get_opt_attr(rule, 'attr')
   filter = _filter_for_rule(rule)
-  bundle_name = None
-  if AppleBundleInfo in target:
-    bundle_name = target[AppleBundleInfo].bundle_name
 
   tulsi_info_files = depset()
   transitive_attributes = dict()
@@ -617,7 +614,23 @@
     if watch_app:
       extensions.append(watch_app)
 
-  bundle_id = _get_opt_attr(rule_attr, 'bundle_id')
+  # Collect bundle related information.
+  if AppleBundleInfo in target:
+    apple_bundle_provider = target[AppleBundleInfo]
+
+    bundle_name = apple_bundle_provider.bundle_name
+    bundle_id = apple_bundle_provider.bundle_id
+    product_type = apple_bundle_provider.product_type
+
+    # We only need the infoplist from iOS extension targets.
+    infoplist = apple_bundle_provider.infoplist if IosExtensionBundleInfo in target else None
+  else:
+    bundle_name = None
+    # For macos_command_line_application, which does not have a AppleBundleInfo
+    # provider but does have a bundle_id attribute for use in the Info.plist.
+    bundle_id = _get_opt_attr(rule_attr, 'bundle_id')
+    product_type = None
+    infoplist = None
 
   # Build up any local transitive attributes and apply them.
   swift_language_version = _extract_swift_language_version(ctx)
@@ -625,13 +638,6 @@
     transitive_attributes['swift_language_version'] = swift_language_version
     transitive_attributes['has_swift_dependency'] = True
 
-  # Collect Info.plist files from an extension to figure out its type.
-  infoplist = None
-
-  # Only Skylark versions of ios_extension have the AppleBundleInfo provider.
-  if IosExtensionBundleInfo in target:
-    infoplist = target[AppleBundleInfo].infoplist
-
   all_attributes = attributes + inheritable_attributes + transitive_attributes
 
   objc_provider = _get_opt_attr(target, 'objc')
@@ -667,6 +673,7 @@
       type=target_kind,
       infoplist=infoplist.basename if infoplist else None,
       platform_type=platform_type,
+      product_type=product_type,
   )
 
   # Create an action to write out this target's info.
diff --git a/src/TulsiGenerator/BazelAspectInfoExtractor.swift b/src/TulsiGenerator/BazelAspectInfoExtractor.swift
index 513e27a..0e16ed5 100644
--- a/src/TulsiGenerator/BazelAspectInfoExtractor.swift
+++ b/src/TulsiGenerator/BazelAspectInfoExtractor.swift
@@ -341,18 +341,33 @@
       }
       let bundleID = dict["bundle_id"] as? String
       let bundleName = dict["bundle_name"] as? String
+      let productType = dict["product_type"] as? String
+
       let platformType = dict["platform_type"] as? String
 
+      let targetProductType: PBXTarget.ProductType?
+
+      if let productTypeStr = productType {
+        // Better be a type that we support, otherwise it's an error on our end.
+        if let actualProductType = PBXTarget.ProductType(rawValue: productTypeStr) {
+          targetProductType = actualProductType
+        } else {
+          throw ExtractorError.parsingFailed("Unsupported product type: \(productTypeStr)")
+        }
+      } else {
+        targetProductType = nil
+      }
+
       var extensionType: String?
-      if ruleType == "ios_extension", let infoplistPath = dict["infoplist"] as? String {
-        // TODO(dmishe): This relies on the fact the Plist will be located next to the .tulsiinfo
-        // file for the same target. It would be better to get an absolute path to the plist from
-        // bazel.
+      if targetProductType?.isiOSAppExtension ?? false, let infoplistPath = dict["infoplist"] as? String {
+        // TODO(b/73349137): This relies on the fact the Plist will be located next to the
+        // .tulsiinfo file for the same target. It would be better to get an absolute path to the
+        // plist from bazel.
         let plistPath = URL(fileURLWithPath: filename)
-            .deletingLastPathComponent()
-            .appendingPathComponent(infoplistPath).path
+          .deletingLastPathComponent()
+          .appendingPathComponent(infoplistPath).path
         guard let info = NSDictionary(contentsOfFile: plistPath) else {
-          throw ExtractorError.parsingFailed("Unable to load ios_extension plist file: \(plistPath)")
+          throw ExtractorError.parsingFailed("Unable to load extension plist file: \(plistPath)")
         }
 
         guard let _extensionType = info.value(forKeyPath: "NSExtension.NSExtensionPointIdentifier") as? String else {
@@ -374,6 +389,7 @@
                                 extensions: extensions,
                                 bundleID: bundleID,
                                 bundleName: bundleName,
+                                productType: targetProductType,
                                 platformType: platformType,
                                 osDeploymentTarget: osDeploymentTarget,
                                 buildFilePath: buildFilePath,
diff --git a/src/TulsiGenerator/PBXObjects.swift b/src/TulsiGenerator/PBXObjects.swift
index 9a04192..1fbec9d 100644
--- a/src/TulsiGenerator/PBXObjects.swift
+++ b/src/TulsiGenerator/PBXObjects.swift
@@ -691,6 +691,9 @@
     case Framework = "com.apple.product-type.framework"
     case StaticFramework = "com.apple.product-type.framework.static"
     case Application = "com.apple.product-type.application"
+    case MessagesApplication = "com.apple.product-type.application.messages"
+    case MessagesExtension = "com.apple.product-type.app-extension.messages"
+    case MessagesStickerPackExtension = "com.apple.product-type.app-extension.messages-sticker-pack"
     case UnitTest = "com.apple.product-type.bundle.unit-test"
     case UIUnitTest = "com.apple.product-type.bundle.ui-testing"
     case InAppPurchaseContent = "com.apple.product-type.in-app-purchase-content"
@@ -707,6 +710,12 @@
       return self == .Watch1App || self == .Watch2App
     }
 
+    /// Whether or not this ProductType is an iOS app extension or variant.
+    var isiOSAppExtension: Bool {
+      return self == .AppExtension || self == .MessagesExtension
+          || self == .MessagesStickerPackExtension
+    }
+
     /// Whether or not this ProductType denotes a test bundle.
     var isTest: Bool {
       return self == .UnitTest || self == .UIUnitTest
@@ -749,6 +758,8 @@
           fallthrough
         case .Watch2App:
           fallthrough
+        case .MessagesApplication:
+          fallthrough
         case .Application:
           return "wrapper.application"
 
@@ -766,6 +777,10 @@
           fallthrough
         case .TVAppExtension:
           fallthrough
+        case .MessagesExtension:
+          fallthrough
+        case .MessagesStickerPackExtension:
+          fallthrough
         case .AppExtension:
           return "wrapper.app-extension"
 
@@ -796,6 +811,8 @@
 
         case .Watch2App:
           fallthrough
+        case .MessagesApplication:
+          fallthrough
         case .Application:
           return "\(name).app"
 
@@ -816,6 +833,10 @@
           fallthrough
         case .TVAppExtension:
           fallthrough
+        case .MessagesExtension:
+          fallthrough
+        case .MessagesStickerPackExtension:
+          fallthrough
         case .AppExtension:
           return "\(name).appex"
 
diff --git a/src/TulsiGenerator/PBXTargetGenerator.swift b/src/TulsiGenerator/PBXTargetGenerator.swift
index 9cf6946..862432d 100644
--- a/src/TulsiGenerator/PBXTargetGenerator.swift
+++ b/src/TulsiGenerator/PBXTargetGenerator.swift
@@ -30,6 +30,10 @@
     case .Watch1Extension, .Watch2Extension:
       return watchOSAppExStub
 
+    case .MessagesExtension:
+      fallthrough
+    case .MessagesStickerPackExtension:
+      fallthrough
     case .AppExtension:
       return stubProjectPath(forRuleEntry: entry)
 
diff --git a/src/TulsiGenerator/RuleEntry.swift b/src/TulsiGenerator/RuleEntry.swift
index a32bc46..1f67449 100644
--- a/src/TulsiGenerator/RuleEntry.swift
+++ b/src/TulsiGenerator/RuleEntry.swift
@@ -131,27 +131,15 @@
   // searched recursively or not.
   public typealias IncludePath = (String, Bool)
 
-  /// Mapping of BUILD file type to Xcode Target type.
+  /// Mapping of BUILD file type to Xcode Target type for non-bundled types.
   static let BuildTypeToTargetType = [
-      "apple_ui_test": PBXTarget.ProductType.UIUnitTest,
-      "apple_unit_test": PBXTarget.ProductType.UnitTest,
       "cc_binary": PBXTarget.ProductType.Application,
       "cc_library": PBXTarget.ProductType.StaticLibrary,
-      "ios_application": PBXTarget.ProductType.Application,
-      "ios_extension": PBXTarget.ProductType.AppExtension,
-      "ios_framework": PBXTarget.ProductType.Framework,
-      "ios_legacy_test": PBXTarget.ProductType.Application,
-      "macos_application": PBXTarget.ProductType.Application,
-      "macos_bundle": PBXTarget.ProductType.Bundle,
+      // macos_command_line_application is not a bundled type in our rules as it does not contain
+      // any resources, so we must explicitly list it here.
       "macos_command_line_application": PBXTarget.ProductType.Tool,
-      "macos_extension": PBXTarget.ProductType.AppExtension,
-      "objc_binary": PBXTarget.ProductType.Application,
       "objc_library": PBXTarget.ProductType.StaticLibrary,
       "swift_library": PBXTarget.ProductType.StaticLibrary,
-      "tvos_application": PBXTarget.ProductType.Application,
-      "tvos_extension": PBXTarget.ProductType.TVAppExtension,
-      "watchos_application": PBXTarget.ProductType.Watch2App,
-      "watchos_extension": PBXTarget.ProductType.Watch2Extension,
   ]
 
   /// Keys for a RuleEntry's attributes map. Definitions may be found in the Bazel Build
@@ -260,6 +248,9 @@
   /// The bundle name associated with the target for this rule, if any.
   public let bundleName: String?
 
+  /// The product type for this rule (only for targets With AppleBundleInfo).
+  let productType: PBXTarget.ProductType?
+
   /// The CFBundleIdentifier of the watchOS extension target associated with this rule, if any.
   public let extensionBundleID: String?
 
@@ -301,6 +292,9 @@
   }
 
   private(set) lazy var pbxTargetType: PBXTarget.ProductType? = { [unowned self] in
+    if let productType = self.productType {
+      return productType
+    }
     return BuildTypeToTargetType[self.type]
   }()
 
@@ -326,6 +320,7 @@
        extensions: Set<BuildLabel>? = nil,
        bundleID: String? = nil,
        bundleName: String? = nil,
+       productType: PBXTarget.ProductType? = nil,
        extensionBundleID: String? = nil,
        platformType: String? = nil,
        osDeploymentTarget: String? = nil,
@@ -371,6 +366,7 @@
     }
     self.bundleID = bundleID
     self.bundleName = bundleName
+    self.productType = productType
     self.extensionBundleID = extensionBundleID
     var deploymentTarget: DeploymentTarget? = nil
     if let platform = parsedPlatformType,
@@ -408,6 +404,7 @@
                    extensions: Set<BuildLabel>? = nil,
                    bundleID: String? = nil,
                    bundleName: String? = nil,
+                   productType: PBXTarget.ProductType? = nil,
                    extensionBundleID: String? = nil,
                    platformType: String? = nil,
                    osDeploymentTarget: String? = nil,
@@ -432,6 +429,7 @@
               extensions: extensions,
               bundleID: bundleID,
               bundleName: bundleName,
+              productType: productType,
               extensionBundleID: extensionBundleID,
               platformType: platformType,
               osDeploymentTarget: osDeploymentTarget,
diff --git a/src/TulsiGenerator/XcodeProjectGenerator.swift b/src/TulsiGenerator/XcodeProjectGenerator.swift
index 170de09..af3e332 100644
--- a/src/TulsiGenerator/XcodeProjectGenerator.swift
+++ b/src/TulsiGenerator/XcodeProjectGenerator.swift
@@ -224,7 +224,7 @@
     installGeneratorConfig(projectURL)
     installGeneratedProjectResources(projectURL)
     installStubExtensionPlistFiles(projectURL,
-                                   rules: projectInfo.buildRuleEntries.filter { $0.pbxTargetType == .AppExtension },
+                                   rules: projectInfo.buildRuleEntries.filter { $0.pbxTargetType?.isiOSAppExtension ?? false },
                                    plistPaths: plistPaths)
     return projectURL
   }
@@ -581,6 +581,10 @@
       let runnableDebuggingMode: XcodeScheme.RunnableDebuggingMode
       let targetType = entry.pbxTargetType ?? .Application
       switch targetType {
+        case .MessagesExtension:
+          fallthrough
+        case .MessagesStickerPackExtension:
+          fallthrough
         case .AppExtension:
           appExtension = true
           launchStyle = .AppExtension
diff --git a/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/ComplexSingleProject.xcodeproj/project.pbxproj b/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/ComplexSingleProject.xcodeproj/project.pbxproj
index 12d8a37..dfa7771 100644
--- a/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/ComplexSingleProject.xcodeproj/project.pbxproj
+++ b/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/ComplexSingleProject.xcodeproj/project.pbxproj
@@ -852,6 +852,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3 $(TULSI_WR)/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_WR)/_tulsi-includes/x/x/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_BWRS)/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_BWRS)/_tulsi-includes/x/x/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = example.iosappTests;
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Application.app/Application";
@@ -1030,6 +1031,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3 $(TULSI_WR)/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_WR)/_tulsi-includes/x/x/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_BWRS)/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes $(TULSI_BWRS)/_tulsi-includes/x/x/tulsi_e2e_complex/SubLibraryWithDifferentDefines/includes";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = example.iosappTests;
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Application.app/Application";
@@ -1214,6 +1216,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = example.iosappTests;
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -1334,6 +1337,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = example.iosappTests;
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
diff --git a/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/IosLegacyTestProject.xcodeproj/project.pbxproj b/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/IosLegacyTestProject.xcodeproj/project.pbxproj
index c881d30..f2c160e 100644
--- a/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/IosLegacyTestProject.xcodeproj/project.pbxproj
+++ b/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/IosLegacyTestProject.xcodeproj/project.pbxproj
@@ -220,6 +220,7 @@
 				GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.google.LegacyTest.LegacyTests;
 				PRODUCT_NAME = LegacyTests;
 				SDKROOT = iphoneos;
 				TULSI_BUILD_PATH = tulsi_e2e_ios_legacy_test;
@@ -286,6 +287,7 @@
 				GCC_PREPROCESSOR_DEFINITIONS = "NDEBUG=1";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.google.LegacyTest.LegacyTests;
 				PRODUCT_NAME = LegacyTests;
 				SDKROOT = iphoneos;
 				TULSI_BUILD_PATH = tulsi_e2e_ios_legacy_test;
@@ -362,6 +364,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.google.LegacyTest.LegacyTests;
 				PRODUCT_NAME = LegacyTests;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -428,6 +431,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.google.LegacyTest.LegacyTests;
 				PRODUCT_NAME = LegacyTests;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
diff --git a/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/MacOSTestsProject.xcodeproj/project.pbxproj b/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/MacOSTestsProject.xcodeproj/project.pbxproj
index 6308b18..6ee3525 100644
--- a/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/MacOSTestsProject.xcodeproj/project.pbxproj
+++ b/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/MacOSTestsProject.xcodeproj/project.pbxproj
@@ -452,6 +452,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				MACOSX_DEPLOYMENT_TARGET = 10.10;
+				PRODUCT_BUNDLE_IDENTIFIER = "com.example.mac-appTests";
 				PRODUCT_NAME = UnitTests;
 				SDKROOT = macosx;
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MyMacOSApp.app/Contents/MacOS/MyMacOSApp";
@@ -490,6 +491,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				MACOSX_DEPLOYMENT_TARGET = 10.10;
+				PRODUCT_BUNDLE_IDENTIFIER = "com.example.mac-appTests";
 				PRODUCT_NAME = UITests;
 				SDKROOT = macosx;
 				TEST_TARGET_NAME = MyMacOSApp;
@@ -545,6 +547,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				MACOSX_DEPLOYMENT_TARGET = 10.10;
+				PRODUCT_BUNDLE_IDENTIFIER = com.tulsi.tests;
 				PRODUCT_NAME = UnitTestsNoHost;
 				SDKROOT = macosx;
 				TULSI_BUILD_PATH = tulsi_e2e_mac;
@@ -591,6 +594,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				MACOSX_DEPLOYMENT_TARGET = 10.10;
+				PRODUCT_BUNDLE_IDENTIFIER = "com.example.mac-appTests";
 				PRODUCT_NAME = UnitTests;
 				SDKROOT = macosx;
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MyMacOSApp.app/Contents/MacOS/MyMacOSApp";
@@ -629,6 +633,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				MACOSX_DEPLOYMENT_TARGET = 10.10;
+				PRODUCT_BUNDLE_IDENTIFIER = "com.example.mac-appTests";
 				PRODUCT_NAME = UITests;
 				SDKROOT = macosx;
 				TEST_TARGET_NAME = MyMacOSApp;
@@ -685,6 +690,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				MACOSX_DEPLOYMENT_TARGET = 10.10;
+				PRODUCT_BUNDLE_IDENTIFIER = com.tulsi.tests;
 				PRODUCT_NAME = UnitTestsNoHost;
 				SDKROOT = macosx;
 				TULSI_BUILD_PATH = tulsi_e2e_mac;
@@ -736,6 +742,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = "com.example.mac-appTests";
 				PRODUCT_NAME = UnitTests;
 				SDKROOT = macosx;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -789,6 +796,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = "com.example.mac-appTests";
 				PRODUCT_NAME = UITests;
 				SDKROOT = macosx;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -856,6 +864,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.tulsi.tests;
 				PRODUCT_NAME = UnitTestsNoHost;
 				SDKROOT = macosx;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -883,6 +892,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = "com.example.mac-appTests";
 				PRODUCT_NAME = UnitTests;
 				SDKROOT = macosx;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -936,6 +946,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = "com.example.mac-appTests";
 				PRODUCT_NAME = UITests;
 				SDKROOT = macosx;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -1004,6 +1015,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.tulsi.tests;
 				PRODUCT_NAME = UnitTestsNoHost;
 				SDKROOT = macosx;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
diff --git a/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/SimpleProject.xcodeproj/project.pbxproj b/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/SimpleProject.xcodeproj/project.pbxproj
index afae3cb..ed3be54 100644
--- a/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/SimpleProject.xcodeproj/project.pbxproj
+++ b/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/SimpleProject.xcodeproj/project.pbxproj
@@ -538,6 +538,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = "application.bundle-idTests";
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Application.app/Application";
@@ -673,6 +674,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = "application.bundle-idTests";
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Application.app/Application";
@@ -814,6 +816,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = "application.bundle-idTests";
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -934,6 +937,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = "application.bundle-idTests";
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
diff --git a/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/SimpleSkylarkProject.xcodeproj/project.pbxproj b/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/SimpleSkylarkProject.xcodeproj/project.pbxproj
index 2945428..4d372c6 100644
--- a/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/SimpleSkylarkProject.xcodeproj/project.pbxproj
+++ b/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/SimpleSkylarkProject.xcodeproj/project.pbxproj
@@ -429,7 +429,7 @@
 			name = StickerExtension;
 			productName = StickerExtension;
 			productReference = 43D68C28947D851600000000 /* StickerExtension.appex */;
-			productType = "com.apple.product-type.app-extension";
+			productType = "com.apple.product-type.app-extension.messages-sticker-pack";
 		};
 		3D31C5E6BECFDF8000000000 /* XCUITest */ = {
 			isa = PBXNativeTarget;
@@ -720,6 +720,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3 $(TULSI_WR)/_tulsi-includes/x/x/tulsi_e2e_simple_skylark/_j2objc/JavaLibrary $(TULSI_WR)/third_party/java_src/j2objc/jre_emul/Classes $(TULSI_WR)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/Classes $(TULSI_WR)/third_party/java_src/j2objc/jre_emul/android/libcore/luni/src/main/native $(TULSI_WR)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/android/libcore/luni/src/main/native $(TULSI_WR)/third_party/java_src/j2objc/jre_emul/android/platform/libcore/ojluni/src/main/native $(TULSI_WR)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/android/platform/libcore/ojluni/src/main/native $(TULSI_WR)/third_party/java_src/j2objc/jre_emul/apple_apsl $(TULSI_WR)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/apple_apsl $(TULSI_WR)/third_party/java_src/j2objc/jre_emul $(TULSI_WR)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul $(TULSI_WR)/third_party/protobuf/objectivec $(TULSI_WR)/_tulsi-includes/x/x/third_party/protobuf/objectivec $(TULSI_BWRS)/_tulsi-includes/x/x/tulsi_e2e_simple_skylark/_j2objc/JavaLibrary $(TULSI_BWRS)/third_party/java_src/j2objc/jre_emul/Classes $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/Classes $(TULSI_BWRS)/third_party/java_src/j2objc/jre_emul/android/libcore/luni/src/main/native $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/android/libcore/luni/src/main/native $(TULSI_BWRS)/third_party/java_src/j2objc/jre_emul/android/platform/libcore/ojluni/src/main/native $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/android/platform/libcore/ojluni/src/main/native $(TULSI_BWRS)/third_party/java_src/j2objc/jre_emul/apple_apsl $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/apple_apsl $(TULSI_BWRS)/third_party/java_src/j2objc/jre_emul $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul $(TULSI_BWRS)/third_party/protobuf/objectivec $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/protobuf/objectivec";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.google.Tulsi.ApplicationTests;
 				PRODUCT_NAME = XCUITest;
 				SDKROOT = iphoneos;
 				TEST_TARGET_NAME = SkylarkApplication;
@@ -759,6 +760,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3 $(TULSI_WR)/_tulsi-includes/x/x/tulsi_e2e_simple_skylark/_j2objc/JavaLibrary $(TULSI_WR)/third_party/java_src/j2objc/jre_emul/Classes $(TULSI_WR)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/Classes $(TULSI_WR)/third_party/java_src/j2objc/jre_emul/android/libcore/luni/src/main/native $(TULSI_WR)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/android/libcore/luni/src/main/native $(TULSI_WR)/third_party/java_src/j2objc/jre_emul/android/platform/libcore/ojluni/src/main/native $(TULSI_WR)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/android/platform/libcore/ojluni/src/main/native $(TULSI_WR)/third_party/java_src/j2objc/jre_emul/apple_apsl $(TULSI_WR)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/apple_apsl $(TULSI_WR)/third_party/java_src/j2objc/jre_emul $(TULSI_WR)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul $(TULSI_WR)/third_party/protobuf/objectivec $(TULSI_WR)/_tulsi-includes/x/x/third_party/protobuf/objectivec $(TULSI_BWRS)/_tulsi-includes/x/x/tulsi_e2e_simple_skylark/_j2objc/JavaLibrary $(TULSI_BWRS)/third_party/java_src/j2objc/jre_emul/Classes $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/Classes $(TULSI_BWRS)/third_party/java_src/j2objc/jre_emul/android/libcore/luni/src/main/native $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/android/libcore/luni/src/main/native $(TULSI_BWRS)/third_party/java_src/j2objc/jre_emul/android/platform/libcore/ojluni/src/main/native $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/android/platform/libcore/ojluni/src/main/native $(TULSI_BWRS)/third_party/java_src/j2objc/jre_emul/apple_apsl $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/apple_apsl $(TULSI_BWRS)/third_party/java_src/j2objc/jre_emul $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul $(TULSI_BWRS)/third_party/protobuf/objectivec $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/protobuf/objectivec";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.google.Tulsi.ApplicationTests;
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				SWIFT_INCLUDE_PATHS = "$(inherited) $(TULSI_BWRS)/_tulsi-includes/x/x/tulsi_e2e_simple_skylark/XCTestCodeSwift/_objs";
@@ -922,6 +924,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3 $(TULSI_WR)/_tulsi-includes/x/x/tulsi_e2e_simple_skylark/_j2objc/JavaLibrary $(TULSI_WR)/third_party/java_src/j2objc/jre_emul/Classes $(TULSI_WR)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/Classes $(TULSI_WR)/third_party/java_src/j2objc/jre_emul/android/libcore/luni/src/main/native $(TULSI_WR)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/android/libcore/luni/src/main/native $(TULSI_WR)/third_party/java_src/j2objc/jre_emul/android/platform/libcore/ojluni/src/main/native $(TULSI_WR)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/android/platform/libcore/ojluni/src/main/native $(TULSI_WR)/third_party/java_src/j2objc/jre_emul/apple_apsl $(TULSI_WR)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/apple_apsl $(TULSI_WR)/third_party/java_src/j2objc/jre_emul $(TULSI_WR)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul $(TULSI_WR)/third_party/protobuf/objectivec $(TULSI_WR)/_tulsi-includes/x/x/third_party/protobuf/objectivec $(TULSI_BWRS)/_tulsi-includes/x/x/tulsi_e2e_simple_skylark/_j2objc/JavaLibrary $(TULSI_BWRS)/third_party/java_src/j2objc/jre_emul/Classes $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/Classes $(TULSI_BWRS)/third_party/java_src/j2objc/jre_emul/android/libcore/luni/src/main/native $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/android/libcore/luni/src/main/native $(TULSI_BWRS)/third_party/java_src/j2objc/jre_emul/android/platform/libcore/ojluni/src/main/native $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/android/platform/libcore/ojluni/src/main/native $(TULSI_BWRS)/third_party/java_src/j2objc/jre_emul/apple_apsl $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/apple_apsl $(TULSI_BWRS)/third_party/java_src/j2objc/jre_emul $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul $(TULSI_BWRS)/third_party/protobuf/objectivec $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/protobuf/objectivec";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.google.Tulsi.ApplicationTests;
 				PRODUCT_NAME = XCUITest;
 				SDKROOT = iphoneos;
 				TEST_TARGET_NAME = SkylarkApplication;
@@ -961,6 +964,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3 $(TULSI_WR)/_tulsi-includes/x/x/tulsi_e2e_simple_skylark/_j2objc/JavaLibrary $(TULSI_WR)/third_party/java_src/j2objc/jre_emul/Classes $(TULSI_WR)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/Classes $(TULSI_WR)/third_party/java_src/j2objc/jre_emul/android/libcore/luni/src/main/native $(TULSI_WR)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/android/libcore/luni/src/main/native $(TULSI_WR)/third_party/java_src/j2objc/jre_emul/android/platform/libcore/ojluni/src/main/native $(TULSI_WR)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/android/platform/libcore/ojluni/src/main/native $(TULSI_WR)/third_party/java_src/j2objc/jre_emul/apple_apsl $(TULSI_WR)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/apple_apsl $(TULSI_WR)/third_party/java_src/j2objc/jre_emul $(TULSI_WR)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul $(TULSI_WR)/third_party/protobuf/objectivec $(TULSI_WR)/_tulsi-includes/x/x/third_party/protobuf/objectivec $(TULSI_BWRS)/_tulsi-includes/x/x/tulsi_e2e_simple_skylark/_j2objc/JavaLibrary $(TULSI_BWRS)/third_party/java_src/j2objc/jre_emul/Classes $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/Classes $(TULSI_BWRS)/third_party/java_src/j2objc/jre_emul/android/libcore/luni/src/main/native $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/android/libcore/luni/src/main/native $(TULSI_BWRS)/third_party/java_src/j2objc/jre_emul/android/platform/libcore/ojluni/src/main/native $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/android/platform/libcore/ojluni/src/main/native $(TULSI_BWRS)/third_party/java_src/j2objc/jre_emul/apple_apsl $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul/apple_apsl $(TULSI_BWRS)/third_party/java_src/j2objc/jre_emul $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/java_src/j2objc/jre_emul $(TULSI_BWRS)/third_party/protobuf/objectivec $(TULSI_BWRS)/_tulsi-includes/x/x/third_party/protobuf/objectivec";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.google.Tulsi.ApplicationTests;
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				SWIFT_INCLUDE_PATHS = "$(inherited) $(TULSI_BWRS)/_tulsi-includes/x/x/tulsi_e2e_simple_skylark/XCTestCodeSwift/_objs";
@@ -1130,6 +1134,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.google.Tulsi.ApplicationTests;
 				PRODUCT_NAME = XCUITest;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -1184,6 +1189,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.google.Tulsi.ApplicationTests;
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				SWIFT_INCLUDE_PATHS = "$(inherited) $(TULSI_BWRS)/_tulsi-includes/x/x/tulsi_e2e_simple_skylark/XCTestCodeSwift/_objs";
@@ -1305,6 +1311,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.google.Tulsi.ApplicationTests;
 				PRODUCT_NAME = XCUITest;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -1359,6 +1366,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.google.Tulsi.ApplicationTests;
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				SWIFT_INCLUDE_PATHS = "$(inherited) $(TULSI_BWRS)/_tulsi-includes/x/x/tulsi_e2e_simple_skylark/XCTestCodeSwift/_objs";
diff --git a/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/TestSuiteExplicitXCTestsProject.xcodeproj/project.pbxproj b/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/TestSuiteExplicitXCTestsProject.xcodeproj/project.pbxproj
index 5a54ec1..51ddc91 100644
--- a/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/TestSuiteExplicitXCTestsProject.xcodeproj/project.pbxproj
+++ b/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/TestSuiteExplicitXCTestsProject.xcodeproj/project.pbxproj
@@ -507,6 +507,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestApplication.app/TestApplication";
@@ -546,6 +547,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestApplication.app/TestApplication";
@@ -567,6 +569,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestApplication.app/TestApplication";
@@ -622,6 +625,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.bazelbuild.rulesapple.Tests;
 				PRODUCT_NAME = LogicTest;
 				SDKROOT = iphoneos;
 				TULSI_BUILD_PATH = TestSuite/One;
@@ -655,6 +659,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestApplication.app/TestApplication";
@@ -694,6 +699,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestApplication.app/TestApplication";
@@ -715,6 +721,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestApplication.app/TestApplication";
@@ -771,6 +778,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.bazelbuild.rulesapple.Tests;
 				PRODUCT_NAME = LogicTest;
 				SDKROOT = iphoneos;
 				TULSI_BUILD_PATH = TestSuite/One;
@@ -809,6 +817,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -863,6 +872,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -891,6 +901,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -958,6 +969,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.bazelbuild.rulesapple.Tests;
 				PRODUCT_NAME = LogicTest;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -985,6 +997,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -1039,6 +1052,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -1067,6 +1081,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = XCTest;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -1135,6 +1150,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.bazelbuild.rulesapple.Tests;
 				PRODUCT_NAME = LogicTest;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
diff --git a/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/TestSuiteLocalTaggedTestsProject.xcodeproj/project.pbxproj b/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/TestSuiteLocalTaggedTestsProject.xcodeproj/project.pbxproj
index 7f27876..976c446 100644
--- a/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/TestSuiteLocalTaggedTestsProject.xcodeproj/project.pbxproj
+++ b/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/TestSuiteLocalTaggedTestsProject.xcodeproj/project.pbxproj
@@ -330,6 +330,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = TestSuiteXCTest;
 				SDKROOT = iphoneos;
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestApplication.app/TestApplication";
@@ -417,6 +418,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = TestSuiteXCTest;
 				SDKROOT = iphoneos;
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestApplication.app/TestApplication";
@@ -510,6 +512,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = TestSuiteXCTest;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -604,6 +607,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = TestSuiteXCTest;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
diff --git a/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/TestSuiteRecursiveTestSuiteProject.xcodeproj/project.pbxproj b/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/TestSuiteRecursiveTestSuiteProject.xcodeproj/project.pbxproj
index 12e6fd2..2a214f1 100644
--- a/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/TestSuiteRecursiveTestSuiteProject.xcodeproj/project.pbxproj
+++ b/src/TulsiGeneratorIntegrationTests/Resources/GoldenProjects/TestSuiteRecursiveTestSuiteProject.xcodeproj/project.pbxproj
@@ -446,6 +446,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = TestSuiteXCTest;
 				SDKROOT = iphoneos;
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestApplication.app/TestApplication";
@@ -485,6 +486,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = tagged_xctest_2;
 				SDKROOT = iphoneos;
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestApplication.app/TestApplication";
@@ -506,6 +508,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = tagged_xctest_1;
 				SDKROOT = iphoneos;
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestApplication.app/TestApplication";
@@ -575,6 +578,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = TestSuiteXCTest;
 				SDKROOT = iphoneos;
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestApplication.app/TestApplication";
@@ -614,6 +618,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = tagged_xctest_2;
 				SDKROOT = iphoneos;
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestApplication.app/TestApplication";
@@ -635,6 +640,7 @@
 				HEADER_SEARCH_PATHS = "$(inherited) $(TULSI_BWRS)/tools/cpp/gcc3";
 				INFOPLIST_FILE = "${PROJECT_FILE_PATH}/.tulsi/Resources/StubInfoPlist.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = tagged_xctest_1;
 				SDKROOT = iphoneos;
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestApplication.app/TestApplication";
@@ -710,6 +716,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = TestSuiteXCTest;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -764,6 +771,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = tagged_xctest_2;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -792,6 +800,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = tagged_xctest_1;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -860,6 +869,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = TestSuiteXCTest;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -914,6 +924,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = tagged_xctest_2;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
@@ -942,6 +953,7 @@
 				OTHER_CFLAGS = "-help";
 				OTHER_LDFLAGS = "-help";
 				OTHER_SWIFT_FLAGS = "-help";
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.testapplicationTests;
 				PRODUCT_NAME = tagged_xctest_1;
 				SDKROOT = iphoneos;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
diff --git a/src/TulsiGeneratorTests/PBXTargetGeneratorTests.swift b/src/TulsiGeneratorTests/PBXTargetGeneratorTests.swift
index 76164c9..ec1b601 100644
--- a/src/TulsiGeneratorTests/PBXTargetGeneratorTests.swift
+++ b/src/TulsiGeneratorTests/PBXTargetGeneratorTests.swift
@@ -160,7 +160,7 @@
 
   func testGenerateBazelCleanTargetAppliesToRulesAddedBeforeAndAfter() {
     do {
-      try targetGenerator.generateBuildTargetsForRuleEntries([makeTestRuleEntry("before", type: "ios_application")], ruleEntryMap: RuleEntryMap())
+      try targetGenerator.generateBuildTargetsForRuleEntries([makeTestRuleEntry("before", type: "ios_application", productType: .Application)], ruleEntryMap: RuleEntryMap())
     } catch let e as NSError {
       XCTFail("Failed to generate build targets with error \(e.localizedDescription)")
     }
@@ -168,7 +168,7 @@
     targetGenerator.generateBazelCleanTarget("scriptPath")
 
     do {
-      try targetGenerator.generateBuildTargetsForRuleEntries([makeTestRuleEntry("after", type: "ios_application")], ruleEntryMap: RuleEntryMap())
+      try targetGenerator.generateBuildTargetsForRuleEntries([makeTestRuleEntry("after", type: "ios_application", productType: .Application)], ruleEntryMap: RuleEntryMap())
     } catch let e as NSError {
       XCTFail("Failed to generate build targets with error \(e.localizedDescription)")
     }
@@ -310,7 +310,7 @@
     let rule2TargetName = "ObjectiveCLibrary"
     let rule2BuildTarget = "\(rule2BuildPath):\(rule2TargetName)"
     let rules = Set([
-      makeTestRuleEntry(rule1BuildTarget, type: "ios_application"),
+      makeTestRuleEntry(rule1BuildTarget, type: "ios_application", productType: .Application),
       makeTestRuleEntry(rule2BuildTarget, type: "objc_library"),
     ])
 
@@ -406,10 +406,12 @@
 
   func testGenerateTargetsForLinkedRuleEntriesWithNoSourcesAndSkylarkUnitTest() {
     checkGenerateTargetsForLinkedRuleEntriesWithNoSources("apple_unit_test",
+                                                          testProductType: .UnitTest,
                                                           testHostAttributeName: "test_host")
   }
 
   func checkGenerateTargetsForLinkedRuleEntriesWithNoSources(_ testRuleType: String,
+                                                             testProductType: PBXTarget.ProductType,
                                                              testHostAttributeName: String) {
     let rule1BuildPath = "test/app"
     let rule1TargetName = "TestApplication"
@@ -419,10 +421,11 @@
     let rule2BuildTarget = "\(rule2BuildPath):\(rule2TargetName)"
     let rule2Attributes = [testHostAttributeName: rule1BuildTarget]
     let rules = Set([
-      makeTestRuleEntry(rule1BuildTarget, type: "ios_application"),
+      makeTestRuleEntry(rule1BuildTarget, type: "ios_application", productType: .Application),
       makeTestRuleEntry(rule2BuildTarget,
                         type: testRuleType,
                         attributes: rule2Attributes as [String: AnyObject],
+                        productType: testProductType,
                         platformType: "ios",
                         osDeploymentTarget: "8.0"),
     ])
@@ -533,10 +536,11 @@
     let rule2BuildTarget = "\(rule2BuildPath):\(rule2TargetName)"
     let rule2Attributes = [testHostAttributeName: rule1BuildTarget]
     let rules = Set([
-      makeTestRuleEntry(rule1BuildTarget, type: "ios_application"),
+      makeTestRuleEntry(rule1BuildTarget, type: "ios_application", productType: .Application),
       makeTestRuleEntry(rule2BuildTarget,
                         type: testRuleType,
                         attributes: rule2Attributes as [String: AnyObject],
+                        productType: .UIUnitTest,
                         platformType: "ios",
                         osDeploymentTarget: "8.0"),
       ])
@@ -648,11 +652,13 @@
     let rules = Set([
       makeTestRuleEntry(rule1BuildTarget,
                         type: "macos_application",
+                        productType: .Application,
                         platformType: "macos",
                         osDeploymentTarget: "10.11"),
       makeTestRuleEntry(rule2BuildTarget,
                         type: testRuleType,
                         attributes: rule2Attributes as [String: AnyObject],
+                        productType: .UnitTest,
                         platformType: "macos",
                         osDeploymentTarget: "10.11"),
       ])
@@ -766,11 +772,13 @@
     let rules = Set([
       makeTestRuleEntry(rule1BuildTarget,
                         type: "macos_application",
+                        productType: .Application,
                         platformType: "macos",
                         osDeploymentTarget: "10.11"),
       makeTestRuleEntry(rule2BuildTarget,
                         type: testRuleType,
                         attributes: rule2Attributes as [String: AnyObject],
+                        productType: .UIUnitTest,
                         platformType: "macos",
                         osDeploymentTarget: "10.11"),
       ])
@@ -878,6 +886,7 @@
     let rules = Set([
       makeTestRuleEntry(rule1BuildTarget,
                         type: testRuleType,
+                        productType: .UnitTest,
                         platformType: "macos",
                         osDeploymentTarget: "10.11"),
       ])
@@ -947,6 +956,7 @@
       makeTestRuleEntry(rule1BuildTarget,
                         type: testRuleType,
                         sourceFiles: testSources,
+                        productType: .UnitTest,
                         platformType: "macos",
                         osDeploymentTarget: "10.11"),
       ])
@@ -1009,10 +1019,12 @@
 
   func testGenerateTargetsForLinkedRuleEntriesWithSourcesWithSkylarkUnitTest() {
     checkGenerateTargetsForLinkedRuleEntriesWithSources("apple_unit_test",
+                                                        testProductType: .UnitTest,
                                                         testHostAttributeName: "test_host")
   }
 
   func checkGenerateTargetsForLinkedRuleEntriesWithSources(_ testRuleType: String,
+                                                           testProductType: PBXTarget.ProductType,
                                                            testHostAttributeName: String) {
     let rule1BuildPath = "test/app"
     let rule1TargetName = "TestHost"
@@ -1026,10 +1038,11 @@
                                      type: testRuleType,
                                      attributes: testRuleAttributes as [String: AnyObject],
                                      sourceFiles: testSources,
+                                     productType: testProductType,
                                      platformType: "ios",
                                      osDeploymentTarget: "8.0")
     let rules = Set([
-      makeTestRuleEntry(rule1BuildTarget, type: "ios_application"),
+      makeTestRuleEntry(rule1BuildTarget, type: "ios_application", productType: .Application),
       testRule,
     ])
     do {
@@ -1142,11 +1155,12 @@
       type: "ios_test_bundle",
       attributes: ["binary": appleBinaryRuleEntry.label.value as AnyObject])
     let testHostRuleEntry = makeTestRuleEntry("\(testRulePackage):\(testHostTargetName)",
-      type: "ios_application")
+      type: "ios_application", productType: .Application)
     let testRuleEntry = makeTestRuleEntry("\(testRulePackage):\(testRuleTargetName)",
       type: "\(testRuleType)",
       attributes: ["test_bundle": testBundleRuleEntry.label.value as AnyObject,
                    "test_host": testHostRuleEntry.label.value as AnyObject],
+      productType: .UnitTest,
       platformType: "ios",
       osDeploymentTarget: "8.0")
 
@@ -1228,11 +1242,12 @@
                                                 type: "ios_test_bundle",
                                                 attributes: ["binary": appleBinaryRuleEntry.label.value as AnyObject])
     let testHostRuleEntry = makeTestRuleEntry("\(testRulePackage):\(testHostTargetName)",
-                                              type: "ios_application")
+                                              type: "ios_application", productType: .Application)
     let testRuleEntry = makeTestRuleEntry("\(testRulePackage):\(testRuleTargetName)",
                                           type: "\(testRuleType)",
                                           attributes: ["test_bundle": testBundleRuleEntry.label.value as AnyObject,
                                                        "test_host": testHostRuleEntry.label.value as AnyObject],
+                                          productType: .UnitTest,
                                           platformType: "ios",
                                           osDeploymentTarget: "8.0")
 
@@ -1309,6 +1324,7 @@
 
   func testGenerateTargetsForLinkedRuleEntriesWithSourcesWithSkylarkUITest() {
     let testRuleType = "apple_ui_test"
+    let testProductType = PBXTarget.ProductType.UIUnitTest
     let testHostAttributeName = "test_host"
     let rule1BuildPath = "test/app"
     let rule1TargetName = "TestApplication"
@@ -1322,10 +1338,11 @@
                                      type: testRuleType,
                                      attributes: testRuleAttributes as [String: AnyObject],
                                      sourceFiles: testSources,
+                                     productType: testProductType,
                                      platformType: "ios",
                                      osDeploymentTarget: "8.0")
     let rules = Set([
-      makeTestRuleEntry(rule1BuildTarget, type: "ios_application"),
+      makeTestRuleEntry(rule1BuildTarget, type: "ios_application", productType: .Application),
       testRule,
       ])
     do {
@@ -1423,16 +1440,16 @@
 
   func testGenerateTargetsForLinkedRuleEntriesWithSameTestHostNameInDifferentPackagesWithSkylarkUnitTest() {
     checkGenerateTargetsForLinkedRuleEntriesWithSameTestHostNameInDifferentPackages(
-        "apple_unit_test", testHostAttributeName: "test_host")
+      "apple_unit_test", testProductType: .UnitTest, testHostAttributeName: "test_host")
   }
 
   func testGenerateTargetsForLinkedRuleEntriesWithSameTestHostNameInDifferentPackagesWithSkylarkUITest() {
     checkGenerateTargetsForLinkedRuleEntriesWithSameTestHostNameInDifferentPackages(
-        "apple_ui_test", testHostAttributeName: "test_host")
+      "apple_ui_test", testProductType: .UIUnitTest, testHostAttributeName: "test_host")
   }
 
   func checkGenerateTargetsForLinkedRuleEntriesWithSameTestHostNameInDifferentPackages(
-      _ testRuleType: String, testHostAttributeName: String) {
+    _ testRuleType: String, testProductType: PBXTarget.ProductType, testHostAttributeName: String) {
     let hostTargetName = "TestHost"
     let host1Package = "test/package/1"
     let host2Package = "test/package/2"
@@ -1448,14 +1465,16 @@
     let test1Rule = makeTestRuleEntry(test1Target,
                                       type: testRuleType,
                                       attributes: [testHostAttributeName: host1Target as AnyObject],
-                                      sourceFiles: testSources)
+                                      sourceFiles: testSources,
+                                      productType: testProductType)
     let test2Rule = makeTestRuleEntry(test2Target,
                                       type: testRuleType,
                                       attributes: [testHostAttributeName: host2Target as AnyObject],
-                                      sourceFiles: testSources)
+                                      sourceFiles: testSources,
+                                      productType: testProductType)
     let rules = Set([
-      makeTestRuleEntry(host1Target, type: "ios_application"),
-      makeTestRuleEntry(host2Target, type: "ios_application"),
+      makeTestRuleEntry(host1Target, type: "ios_application", productType: .Application),
+      makeTestRuleEntry(host2Target, type: "ios_application", productType: .Application),
       test1Rule,
       test2Rule,
     ])
@@ -1490,7 +1509,8 @@
     let testRule = makeTestRuleEntry(testRuleBuildTarget,
                                      type: testRuleType,
                                      attributes: testRuleAttributes as [String: AnyObject],
-                                     sourceFiles: testSources)
+                                     sourceFiles: testSources,
+                                     productType: .Application)
     do {
       try targetGenerator.generateBuildTargetsForRuleEntries([testRule], ruleEntryMap: RuleEntryMap())
     } catch let e as NSError {
@@ -1554,8 +1574,8 @@
     let rule2BuildPath = "test/test2"
     let rule2BuildTarget = "\(rule2BuildPath):\(targetName)"
     let rules = Set([
-      makeTestRuleEntry(rule1BuildTarget, type: "ios_application"),
-      makeTestRuleEntry(rule2BuildTarget, type: "ios_application"),
+      makeTestRuleEntry(rule1BuildTarget, type: "ios_application", productType: .Application),
+      makeTestRuleEntry(rule2BuildTarget, type: "ios_application", productType: .Application),
     ])
 
     do {
@@ -1656,7 +1676,8 @@
     let rules = Set([
       makeTestRuleEntry(buildTarget,
                         type: "ios_application",
-                        bundleID: bundleID),
+                        bundleID: bundleID,
+                        productType: .Application),
     ])
 
     do {
@@ -1720,7 +1741,8 @@
     let rules = Set([
       makeTestRuleEntry(buildTarget,
                         type: "ios_application",
-                        bundleName: bundleName),
+                        bundleName: bundleName,
+                        productType: .Application),
       ])
 
     do {
@@ -1795,18 +1817,21 @@
                         type: "ios_application",
                         extensions: Set([BuildLabel(watchAppBuildTarget)]),
                         bundleID: appBundleID,
+                        productType: .Application,
                         platformType: "ios",
                         osDeploymentTarget: "9.0"),
       makeTestRuleEntry(watchAppBuildTarget,
                         type: "watchos_application",
                         extensions: Set([BuildLabel(watchExtBuildTarget)]),
                         bundleID: watchAppBundleID,
+                        productType: .Watch2App,
                         extensionBundleID: watchExtBundleID,
                         platformType: "watchos",
                         osDeploymentTarget: "2.0"),
       makeTestRuleEntry(watchExtBuildTarget,
                         type: "watchos_extension",
                         bundleID: watchExtBundleID,
+                        productType: .Watch2Extension,
                         platformType: "watchos",
                         osDeploymentTarget: "2.0")
     ])
@@ -1964,16 +1989,19 @@
                         type: "macos_application",
                         extensions: Set([BuildLabel(macAppExtBuildTarget)]),
                         bundleID: appBundleID,
+                        productType: .Application,
                         platformType: "macos",
                         osDeploymentTarget: "10.12"),
       makeTestRuleEntry(macAppExtBuildTarget,
                         type: "macos_extension",
                         bundleID: macAppExtBundleID,
+                        productType: .AppExtension,
                         platformType: "macos",
                         osDeploymentTarget: "10.12"),
       makeTestRuleEntry(macCLIAppBuildTarget,
                         type: "macos_command_line_application",
                         bundleID: macCLIAppBundleID,
+                        productType: .Tool,
                         platformType: "macos",
                         osDeploymentTarget: "10.12")
       ])
@@ -2544,7 +2572,8 @@
     let testRule = makeTestRuleEntry(target,
                                      type: targetType,
                                      attributes: ["has_swift_dependency": true as AnyObject],
-                                     dependencies: Set([BuildLabel(swiftTarget)]))
+                                     dependencies: Set([BuildLabel(swiftTarget)]),
+                                     productType: .Application)
     let swiftLibraryRule = makeTestRuleEntry(swiftTarget, type: "swift_library")
     let ruleEntryMap = makeRuleEntryMap(withRuleEntries: [swiftLibraryRule])
 
@@ -2658,6 +2687,7 @@
                                  extensions: Set<BuildLabel>? = nil,
                                  bundleID: String? = nil,
                                  bundleName: String? = nil,
+                                 productType: PBXTarget.ProductType? = nil,
                                  extensionBundleID: String? = nil,
                                  platformType: String? = nil,
                                  osDeploymentTarget: String? = nil,
@@ -2672,6 +2702,7 @@
                              extensions: extensions,
                              bundleID: bundleID,
                              bundleName: bundleName,
+                             productType: productType,
                              extensionBundleID: extensionBundleID,
                              platformType: platformType,
                              osDeploymentTarget: osDeploymentTarget,
@@ -2694,6 +2725,7 @@
                                  extensions: Set<BuildLabel>? = nil,
                                  bundleID: String? = nil,
                                  bundleName: String? = nil,
+                                 productType: PBXTarget.ProductType? = nil,
                                  extensionBundleID: String? = nil,
                                  platformType: String? = nil,
                                  osDeploymentTarget: String? = nil,
@@ -2710,6 +2742,7 @@
                      extensions: extensions,
                      bundleID: bundleID,
                      bundleName: bundleName,
+                     productType: productType,
                      extensionBundleID: extensionBundleID,
                      platformType: platformType,
                      osDeploymentTarget: osDeploymentTarget,
diff --git a/src/TulsiGeneratorTests/XcodeProjectGeneratorTests.swift b/src/TulsiGeneratorTests/XcodeProjectGeneratorTests.swift
index b029c78..9854523 100644
--- a/src/TulsiGeneratorTests/XcodeProjectGeneratorTests.swift
+++ b/src/TulsiGeneratorTests/XcodeProjectGeneratorTests.swift
@@ -89,20 +89,22 @@
                  attributes: [String: AnyObject] = [:],
                  weakDependencies: Set<BuildLabel>? = nil,
                  extensions: Set<BuildLabel>? = nil,
-                 extensionType: String? = nil) -> BuildLabel {
+                 extensionType: String? = nil,
+                 productType: PBXTarget.ProductType? = nil) -> BuildLabel {
       let label = BuildLabel(labelName)
       mockExtractor.labelToRuleEntry[label] = type(of: self).makeRuleEntry(label,
                                                                            type: type,
                                                                            attributes: attributes,
                                                                            weakDependencies: weakDependencies,
                                                                            extensions: extensions,
+                                                                           productType: productType,
                                                                            extensionType: extensionType)
       return label
     }
 
-    let test1 = addRule("//test:ExtFoo", type: "ios_extension", extensionType: "com.apple.extension-foo")
-    let test2 = addRule("//test:ExtBar", type: "ios_extension", extensionType: "com.apple.extension-bar")
-    addRule("//test:Application", type: "ios_application", extensions: [test1, test2])
+    let test1 = addRule("//test:ExtFoo", type: "ios_extension", extensionType: "com.apple.extension-foo", productType: .AppExtension)
+    let test2 = addRule("//test:ExtBar", type: "ios_extension", extensionType: "com.apple.extension-bar", productType: .AppExtension)
+    addRule("//test:Application", type: "ios_application", extensions: [test1, test2], productType: .Application)
     prepareGenerator(mockExtractor.labelToRuleEntry)
 
     func assertPlist(withData data: Data, equalTo value: NSDictionary) {
@@ -163,31 +165,45 @@
   }
 
   func testTestSuiteSchemeGenerationWithSkylarkUnitTest() {
-    checkTestSuiteSchemeGeneration("apple_unit_test", testHostAttributeName: "test_host")
+    checkTestSuiteSchemeGeneration("apple_unit_test",
+                                   testProductType: .UnitTest,
+                                   testHostAttributeName: "test_host")
   }
 
   func testTestSuiteSchemeGenerationWithSkylarkUITest() {
-    checkTestSuiteSchemeGeneration("apple_ui_test", testHostAttributeName: "test_host")
+    checkTestSuiteSchemeGeneration("apple_ui_test",
+                                   testProductType: .UIUnitTest,
+                                   testHostAttributeName: "test_host")
   }
 
-  func checkTestSuiteSchemeGeneration(_ testRuleType: String, testHostAttributeName: String) {
+  func checkTestSuiteSchemeGeneration(_ testRuleType: String,
+                                      testProductType: PBXTarget.ProductType,
+                                      testHostAttributeName: String) {
     @discardableResult
     func addRule(_ labelName: String,
                  type: String,
                  attributes: [String: AnyObject] = [:],
-                 weakDependencies: Set<BuildLabel>? = nil) -> BuildLabel {
+                 weakDependencies: Set<BuildLabel>? = nil,
+                 productType: PBXTarget.ProductType? = nil) -> BuildLabel {
       let label = BuildLabel(labelName)
       mockExtractor.labelToRuleEntry[label] = type(of: self).makeRuleEntry(label,
                                                                              type: type,
                                                                              attributes: attributes,
-                                                                             weakDependencies: weakDependencies)
+                                                                             weakDependencies: weakDependencies,
+                                                                             productType: productType)
       return label
     }
 
-    let app = addRule("//test:Application", type: "ios_application")
-    let test1 = addRule("//test:TestOne", type: testRuleType, attributes: [testHostAttributeName: app.value as AnyObject])
-    let test2 = addRule("//test:TestTwo", type: testRuleType, attributes: [testHostAttributeName: app.value as AnyObject])
-    addRule("//test:UnusedTest", type: testRuleType)
+    let app = addRule("//test:Application", type: "ios_application", productType: .Application)
+    let test1 = addRule("//test:TestOne",
+                        type: testRuleType,
+                        attributes: [testHostAttributeName: app.value as AnyObject],
+                        productType: testProductType)
+    let test2 = addRule("//test:TestTwo",
+                        type: testRuleType,
+                        attributes: [testHostAttributeName: app.value as AnyObject],
+                        productType: testProductType)
+    addRule("//test:UnusedTest", type: testRuleType, productType: testProductType)
     addRule("//test:TestSuite", type: "test_suite", weakDependencies: Set([test1, test2]))
     prepareGenerator(mockExtractor.labelToRuleEntry)
 
@@ -234,7 +250,7 @@
   private static func labelToRuleEntryMapForLabels(_ labels: [BuildLabel]) -> [BuildLabel: RuleEntry] {
     var ret = [BuildLabel: RuleEntry]()
     for label in labels {
-      ret[label] = makeRuleEntry(label, type: "ios_application")
+      ret[label] = makeRuleEntry(label, type: "ios_application", productType: .Application)
     }
     return ret
   }
@@ -252,6 +268,7 @@
                                     defines: [String]? = nil,
                                     includePaths: [RuleEntry.IncludePath]? = nil,
                                     extensions: Set<BuildLabel>? = nil,
+                                    productType: PBXTarget.ProductType? = nil,
                                     extensionType: String? = nil,
                                     platformType: String? = nil,
                                     osDeploymentTarget: String? = nil) -> RuleEntry {
@@ -265,6 +282,7 @@
                      secondaryArtifacts: secondaryArtifacts,
                      weakDependencies: weakDependencies,
                      extensions: extensions,
+                     productType: productType,
                      platformType: platformType,
                      osDeploymentTarget: osDeploymentTarget,
                      buildFilePath: buildFilePath,