2016-05-26 16:06:52 +03:00
using System ;
2017-01-16 18:23:49 +03:00
using System.Collections.Generic ;
2016-05-26 16:06:52 +03:00
using System.IO ;
using System.Xml ;
2019-02-20 08:30:57 +03:00
2018-12-12 17:55:57 +03:00
using Xamarin ;
2019-02-20 08:30:57 +03:00
using Xamarin.Utils ;
2016-05-26 16:06:52 +03:00
namespace xharness
{
2017-09-22 19:04:32 +03:00
public class WatchOSTarget : iOSTarget
2016-05-26 16:06:52 +03:00
{
public string AppName { get ; private set ; }
public string ExtensionName { get ; private set ; }
public string WatchOSAppGuid { get ; private set ; }
public string WatchOSExtensionGuid { get ; private set ; }
public string WatchOSGuid { get { return ProjectGuid ; } private set { ProjectGuid = value ; } }
public string WatchOSAppProjectPath { get ; private set ; }
public string WatchOSExtensionProjectPath { get ; private set ; }
public string WatchOSProjectPath { get { return ProjectPath ; } private set { ProjectPath = value ; } }
void CreateWatchOSAppProject ( )
{
var csproj = new XmlDocument ( ) ;
2018-11-14 21:26:30 +03:00
var suffix = Suffix + "-app" ;
2016-05-26 16:06:52 +03:00
csproj . LoadWithoutNetworkAccess ( Path . Combine ( Harness . WatchOSAppTemplate , "App.csproj" ) ) ;
csproj . FindAndReplace ( "%WATCHAPP_PATH%" , Path . GetFullPath ( Harness . WatchOSAppTemplate ) . Replace ( '/' , '\\' ) + "\\" ) ;
csproj . FindAndReplace ( "%WATCHEXTENSION_CSPROJ%" , Path . GetFileName ( WatchOSExtensionProjectPath ) ) ;
csproj . SetProjectReferenceValue ( Path . GetFileName ( WatchOSExtensionProjectPath ) , "Project" , WatchOSExtensionGuid ) ;
2016-06-09 17:24:32 +03:00
csproj . SetProjectReferenceValue ( Path . GetFileName ( WatchOSExtensionProjectPath ) , "Name" , Path . GetFileNameWithoutExtension ( WatchOSExtensionProjectPath ) ) ;
2016-05-26 16:06:52 +03:00
WatchOSAppGuid = "{" + Harness . NewStableGuid ( ) . ToString ( ) . ToUpper ( ) + "}" ;
csproj . SetProjectGuid ( WatchOSAppGuid ) ;
2017-01-04 21:45:26 +03:00
csproj . FixInfoPListInclude ( suffix ) ;
2018-11-14 21:26:30 +03:00
if ( MonoNativeInfo ! = null ) {
csproj . AddAdditionalDefines ( "MONO_NATIVE_WATCH" ) ;
MonoNativeHelper . AddProjectDefines ( csproj , MonoNativeInfo . Flavor ) ;
MonoNativeHelper . RemoveSymlinkMode ( csproj ) ;
}
2016-05-26 16:06:52 +03:00
Harness . Save ( csproj , WatchOSAppProjectPath ) ;
XmlDocument info_plist = new XmlDocument ( ) ;
2018-11-14 21:26:30 +03:00
var target_info_plist = Path . Combine ( TargetDirectory , $"Info{Suffix}-app.plist" ) ;
2016-05-26 16:06:52 +03:00
info_plist . LoadWithoutNetworkAccess ( Path . Combine ( Harness . WatchOSAppTemplate , "Info.plist" ) ) ;
info_plist . SetCFBundleIdentifier ( BundleIdentifier + ".watchkitapp" ) ;
info_plist . SetPListStringValue ( "WKCompanionAppBundleIdentifier" , BundleIdentifier ) ;
info_plist . SetPListStringValue ( "CFBundleName" , Name ) ;
2018-11-14 21:26:30 +03:00
info_plist . SetMinimumOSVersion ( GetMinimumOSVersion ( info_plist . GetMinimumOSVersion ( ) ) ) ;
2016-05-26 16:06:52 +03:00
Harness . Save ( info_plist , target_info_plist ) ;
}
void CreateWatchOSContainerProject ( )
{
var csproj = new XmlDocument ( ) ;
csproj . LoadWithoutNetworkAccess ( Path . Combine ( Harness . WatchOSContainerTemplate , "Container.csproj" ) ) ;
csproj . FindAndReplace ( "%CONTAINER_PATH%" , Path . GetFullPath ( Harness . WatchOSContainerTemplate ) . Replace ( '/' , '\\' ) + "\\" ) ;
csproj . FindAndReplace ( "%WATCHAPP_CSPROJ%" , Path . GetFileName ( WatchOSAppProjectPath ) ) ;
2016-06-09 17:24:32 +03:00
csproj . SetProjectReferenceValue ( Path . GetFileName ( WatchOSAppProjectPath ) , "Name" , Path . GetFileNameWithoutExtension ( WatchOSAppProjectPath ) ) ;
2016-05-26 16:06:52 +03:00
WatchOSGuid = "{" + Harness . NewStableGuid ( ) . ToString ( ) . ToUpper ( ) + "}" ;
csproj . SetProjectGuid ( WatchOSGuid ) ;
2018-11-14 21:26:30 +03:00
csproj . FixInfoPListInclude ( Suffix ) ;
if ( MonoNativeInfo ! = null ) {
csproj . AddAdditionalDefines ( "MONO_NATIVE_WATCH" ) ;
MonoNativeHelper . AddProjectDefines ( csproj , MonoNativeInfo . Flavor ) ;
MonoNativeHelper . RemoveSymlinkMode ( csproj ) ;
}
2016-05-26 16:06:52 +03:00
Harness . Save ( csproj , WatchOSProjectPath ) ;
XmlDocument info_plist = new XmlDocument ( ) ;
2018-11-14 21:26:30 +03:00
var target_info_plist = Path . Combine ( TargetDirectory , $"Info{Suffix}.plist" ) ;
2016-05-26 16:06:52 +03:00
info_plist . LoadWithoutNetworkAccess ( Path . Combine ( Harness . WatchOSContainerTemplate , "Info.plist" ) ) ;
info_plist . SetCFBundleIdentifier ( BundleIdentifier ) ;
info_plist . SetCFBundleName ( Name ) ;
2018-11-14 21:26:30 +03:00
info_plist . SetMinimumOSVersion ( "9.0" ) ;
2016-05-26 16:06:52 +03:00
Harness . Save ( info_plist , target_info_plist ) ;
}
void CreateWatchOSExtensionProject ( )
{
var csproj = inputProject ;
2018-11-14 21:26:30 +03:00
var suffix = Suffix + "-extension" ;
2016-05-26 16:06:52 +03:00
csproj . SetProjectTypeGuids ( "{1E2E965C-F6D2-49ED-B86E-418A60C69EEF};" + LanguageGuid ) ;
csproj . SetOutputPath ( "bin\\$(Platform)\\$(Configuration)" + suffix ) ;
csproj . SetIntermediateOutputPath ( "obj\\$(Platform)\\$(Configuration)" + suffix ) ;
csproj . RemoveTargetFrameworkIdentifier ( ) ;
csproj . SetPlatformAssembly ( "Xamarin.WatchOS" ) ;
csproj . SetImport ( IsFSharp ? "$(MSBuildExtensionsPath)\\Xamarin\\WatchOS\\Xamarin.WatchOS.AppExtension.FSharp.targets" : "$(MSBuildExtensionsPath)\\Xamarin\\WatchOS\\Xamarin.WatchOS.AppExtension.CSharp.targets" ) ;
csproj . FixProjectReferences ( "-watchos" ) ;
csproj . FixArchitectures ( "i386" , "ARMv7k" ) ;
csproj . FixInfoPListInclude ( suffix ) ;
csproj . SetOutputType ( "Library" ) ;
2017-10-05 14:41:04 +03:00
csproj . AddAdditionalDefines ( "BITCODE" , "iPhone" , "Release" ) ;
2019-01-10 17:23:42 +03:00
csproj . AddAdditionalDefines ( "XAMCORE_2_0;XAMCORE_3_0;FEATURE_NO_BSD_SOCKETS;MONOTOUCH_WATCH;" ) ;
2016-11-01 20:13:52 +03:00
csproj . RemoveReferences ( "OpenTK-1.0" ) ;
2016-05-26 16:06:52 +03:00
var ext = IsFSharp ? "fs" : "cs" ;
csproj . AddCompileInclude ( "InterfaceController." + ext , Path . Combine ( Harness . WatchOSExtensionTemplate , "InterfaceController." + ext ) ) ;
2018-11-14 21:26:30 +03:00
csproj . SetExtraLinkerDefs ( "extra-linker-defs" + ExtraLinkerDefsSuffix + ".xml" ) ;
2016-05-26 16:06:52 +03:00
csproj . SetMtouchUseBitcode ( true , "iPhone" , "Release" ) ;
csproj . SetMtouchUseLlvm ( true , "iPhone" , "Release" ) ;
2018-11-14 21:26:30 +03:00
if ( MonoNativeInfo ! = null ) {
csproj . AddAdditionalDefines ( "MONO_NATIVE_WATCH" ) ;
MonoNativeHelper . AddProjectDefines ( csproj , MonoNativeInfo . Flavor ) ;
MonoNativeHelper . RemoveSymlinkMode ( csproj ) ;
}
2018-09-06 11:16:53 +03:00
// Not linking a watch extensions requires passing -Os to the native compiler.
// https://github.com/mono/mono/issues/9867
var configurations = new string [ ] { "Debug" , "Debug32" , "Release" , "Release32" , "Release-bitcode" } ;
2019-02-20 08:30:57 +03:00
foreach ( var c in configurations ) {
var flags = "-fembed-bitcode-marker" ;
2018-09-06 11:16:53 +03:00
if ( csproj . GetMtouchLink ( "iPhone" , c ) = = "None" )
2019-02-20 08:30:57 +03:00
flags + = " -Os" ;
csproj . AddExtraMtouchArgs ( $"--gcc_flags='{flags}'" , "iPhone" , c ) ;
}
2018-09-06 11:16:53 +03:00
2016-05-26 16:06:52 +03:00
Harness . Save ( csproj , WatchOSExtensionProjectPath ) ;
WatchOSExtensionGuid = csproj . GetProjectGuid ( ) ;
XmlDocument info_plist = new XmlDocument ( ) ;
2018-11-14 21:26:30 +03:00
var target_info_plist = Path . Combine ( TargetDirectory , $"Info{Suffix}-extension.plist" ) ;
2016-05-26 16:06:52 +03:00
info_plist . LoadWithoutNetworkAccess ( Path . Combine ( TargetDirectory , "Info.plist" ) ) ;
2017-01-16 20:34:57 +03:00
BundleIdentifier = info_plist . GetCFBundleIdentifier ( ) + "-watch" ;
if ( BundleIdentifier . Length > = 58 )
BundleIdentifier = BundleIdentifier . Substring ( 0 , 57 ) ; // If the main app's bundle id is 58 characters (or sometimes more), then the watch extension crashes at launch. radar #29847128.
2016-05-26 16:06:52 +03:00
info_plist . SetCFBundleIdentifier ( BundleIdentifier + ".watchkitapp.watchkitextension" ) ;
2018-11-14 21:26:30 +03:00
info_plist . SetMinimumOSVersion ( GetMinimumOSVersion ( "2.0" ) ) ;
2016-05-26 16:06:52 +03:00
info_plist . SetUIDeviceFamily ( 4 ) ;
info_plist . AddPListStringValue ( "RemoteInterfacePrincipleClass" , "InterfaceController" ) ;
info_plist . AddPListKeyValuePair ( "NSExtension" , "dict" , string . Format (
@ "
< key > NSExtensionAttributes < / key >
< dict >
< key > WKAppBundleIdentifier < / key >
< string > { 0 } . watchkitapp < / string >
< / dict >
< key > NSExtensionPointIdentifier < / key >
< string > com . apple . watchkit < / string >
", BundleIdentifier));
if ( ! info_plist . ContainsKey ( "NSAppTransportSecurity" ) ) {
info_plist . AddPListKeyValuePair ( "NSAppTransportSecurity" , "dict" ,
@ "
< key > NSAllowsArbitraryLoads < / key >
< true / >
");
}
Harness . Save ( info_plist , target_info_plist ) ;
}
protected override string Imports {
get {
return IsFSharp ? "$(MSBuildExtensionsPath)\\Xamarin\\WatchOS\\Xamarin.WatchOS.FSharp.targets" : "$(MSBuildExtensionsPath)\\Xamarin\\WatchOS\\Xamarin.WatchOS.CSharp.targets" ;
}
}
protected override string BindingsImports {
get {
return IsFSharp ? "$(MSBuildExtensionsPath)\\Xamarin\\WatchOS\\Xamarin.WatchOS.ObjCBinding.FSharp.targets" : "$(MSBuildExtensionsPath)\\Xamarin\\WatchOS\\Xamarin.WatchOS.ObjCBinding.CSharp.targets" ;
}
}
void CreateWatchOSLibraryProject ( )
{
var csproj = inputProject ;
csproj . SetProjectTypeGuids ( "{FC940695-DFE0-4552-9F25-99AF4A5619A1};" + LanguageGuid ) ;
csproj . SetOutputPath ( "bin\\$(Platform)\\$(Configuration)" + Suffix ) ;
csproj . SetIntermediateOutputPath ( "obj\\$(Platform)\\$(Configuration)" + Suffix ) ;
csproj . RemoveTargetFrameworkIdentifier ( ) ;
csproj . SetPlatformAssembly ( "Xamarin.WatchOS" ) ;
csproj . SetImport ( IsBindingProject ? BindingsImports : Imports ) ;
2019-01-10 17:23:42 +03:00
csproj . AddAdditionalDefines ( "XAMCORE_2_0;XAMCORE_3_0;MONOTOUCH_WATCH;" ) ;
2016-05-26 16:06:52 +03:00
csproj . FixProjectReferences ( Suffix ) ;
2018-11-14 21:26:30 +03:00
csproj . SetExtraLinkerDefs ( "extra-linker-defs" + ExtraLinkerDefsSuffix + ".xml" ) ;
2016-05-26 16:06:52 +03:00
csproj . FixTestLibrariesReferences ( Platform ) ;
Harness . Save ( csproj , WatchOSProjectPath ) ;
WatchOSGuid = csproj . GetProjectGuid ( ) ;
}
protected override void ExecuteInternal ( )
{
ExtensionName = Name + " Extension" ;
AppName = Name + " App" ;
2018-11-14 21:26:30 +03:00
var templateName = Path . GetFileName ( TemplateProjectPath ) ;
if ( templateName . EndsWith ( ".template" , StringComparison . OrdinalIgnoreCase ) )
templateName = Path . GetFileNameWithoutExtension ( templateName ) ;
templateName = Path . GetFileNameWithoutExtension ( templateName ) ;
2016-05-26 16:06:52 +03:00
switch ( OutputType ) {
case "Exe" :
2018-11-14 21:26:30 +03:00
WatchOSExtensionProjectPath = Path . Combine ( TargetDirectory , templateName + Suffix + "-extension.csproj" ) ;
WatchOSAppProjectPath = Path . Combine ( TargetDirectory , templateName + Suffix + "-app.csproj" ) ;
2016-05-26 16:06:52 +03:00
CreateWatchOSExtensionProject ( ) ;
CreateWatchOSAppProject ( ) ;
CreateWatchOSContainerProject ( ) ;
break ;
case "Library" :
CreateWatchOSLibraryProject ( ) ;
break ;
default :
throw new Exception ( string . Format ( "Unknown OutputType: {0}" , OutputType ) ) ;
}
}
2018-11-14 21:26:30 +03:00
protected override void CalculateName ( )
{
base . CalculateName ( ) ;
if ( MonoNativeInfo ! = null )
Name = Name + MonoNativeInfo . FlavorSuffix ;
}
protected override string GetMinimumOSVersion ( string templateMinimumOSVersion )
{
if ( MonoNativeInfo = = null )
return templateMinimumOSVersion ;
return MonoNativeHelper . GetMinimumOSVersion ( DevicePlatform . watchOS , MonoNativeInfo . Flavor ) ;
}
2016-05-26 16:06:52 +03:00
public override string Suffix {
2018-11-14 21:26:30 +03:00
get {
return MonoNativeInfo ! = null ? MonoNativeInfo . FlavorSuffix + "-watchos" : "-watchos" ;
}
}
public override string ExtraLinkerDefsSuffix {
2016-05-26 16:06:52 +03:00
get {
return "-watchos" ;
}
}
public override string Platform {
get {
return "watchos" ;
}
}
protected override bool SupportsBitcode {
get {
return true ;
}
}
2017-01-16 18:23:49 +03:00
public override IEnumerable < RelatedProject > GetRelatedProjects ( )
{
return new RelatedProject [ ] {
new RelatedProject { Guid = WatchOSExtensionGuid , ProjectPath = WatchOSExtensionProjectPath } ,
new RelatedProject { Guid = WatchOSAppGuid , ProjectPath = WatchOSAppProjectPath } ,
} ;
}
2016-05-26 16:06:52 +03:00
}
}