diff --git a/docs/TOC.yml b/docs/TOC.yml index cca22d85b..ca75db264 100644 --- a/docs/TOC.yml +++ b/docs/TOC.yml @@ -383,6 +383,8 @@ href: user-interface/controls/tableview.md - name: ContentView href: user-interface/controls/contentview.md + - name: TwoPaneView + href: user-interface/controls/twopaneview.md - name: Display pop-ups href: user-interface/pop-ups.md - name: Display tooltips @@ -630,7 +632,11 @@ - name: Publish items: - name: Android - href: android/deployment/overview.md + items: + - name: Overview + href: android/deployment/overview.md + - name: Publish with the .NET CLI + href: android/deployment/publish-cli.md - name: iOS items: - name: Publish an iOS app @@ -642,6 +648,12 @@ - name: macOS href: macos/deployment/overview.md - name: Windows - href: windows/deployment/overview.md + items: + - name: Overview + href: windows/deployment/overview.md + - name: Publish with the .NET CLI + href: windows/deployment/publish-cli.md + - name: Publish with Visual Studio to a folder + href: windows/deployment/publish-visual-studio-folder.md - name: Troubleshooting href: troubleshooting.md diff --git a/docs/android/deployment/media/overview/build-and-deploy-steps.svg b/docs/android/deployment/media/overview/build-and-deploy-steps.svg new file mode 100644 index 000000000..819d1ef1a --- /dev/null +++ b/docs/android/deployment/media/overview/build-and-deploy-steps.svg @@ -0,0 +1,363 @@ + + + +Prepare for deploymentCompile app for releaseCreate a private key, oruse an existing trusted keySign the APKGoogle PlayAmazon app storeSide-loaded fileDistribute package diff --git a/docs/android/deployment/overview.md b/docs/android/deployment/overview.md index 5f4972c97..2c681d6f5 100644 --- a/docs/android/deployment/overview.md +++ b/docs/android/deployment/overview.md @@ -1,7 +1,7 @@ --- title: "Publish a .NET MAUI app for Android" description: "Learn how to package and publish an Android .NET MAUI app." -ms.date: 03/17/2022 +ms.date: 10/07/2022 --- # Publish a .NET MAUI app for Android @@ -13,133 +13,54 @@ ms.date: 03/17/2022 > - [Publish for macOS](../../macos/deployment/overview.md) > - [Publish for Windows](../../windows/deployment/overview.md) -When distributing your .NET Multi-platform App UI (.NET MAUI) app for Android, you generate an _apk_ (Android Package) or an _aab_ (Android App Bundle) file. The _apk_ is used for installing your app to an Android device, and the _aab_ is used to publish your app to an Android store. +The final step in the development of a .NET MAUI app is to publish it. Publishing is the process of creating a package that contains the app and is ready for users to install on their devices. Packaging and deployment involve two essential tasks: -With just a few configuration changes to your project, your app can be packaged for distribution. +- **Preparing for publication** -## Validate package settings + A release version of the app is created that can be deployed to Android devices. -Every Android app specifies a unique package identifier and a version. These identifiers are generally set in the Android app manifest file, which is located in your project folder at _.\\Platforms\\Android\\AndroidManifest.xml_. However, these specific settings are provided by the project file itself. When a .NET MAUI app is built, the final _AndroidManifest.xml_ file is automatically generated using the project file and the original _AndroidManifest.xml_ file. +- **Distribution** -Your project file must declare `` and `` within a `` node. These items should have been generated for you when the project was created. Just validate that they exist and are set to valid values: + The release version of an app is made available through one or more of the various distribution channels. -```xml - +The following diagram illustrates the steps involved with publishing a .NET MAUI app: - +:::image type="content" source="media/overview/build-and-deploy-steps.svg" alt-text="Build and deploy flowchart"::: - - com.companyname.myproject - 1 - +As can be seen by the diagram above, the preparation is the same regardless of the distribution method that is used. There are several ways that an Android app may be released to users: - -``` +- **Via a website** – A .NET MAUI app can be made available for download on a website, from which users may then install the app by clicking on a link. +- **Via a file share** – Similar to a website, as long as the app package is available to the user, they can side-load it on their device. +- **Through a market** – There are several Android marketplaces that exist for distribution, such as [Google Play](https://play.google.com/) or [Amazon App Store for Android](https://www.amazon.com/mobile-apps/b?ie=UTF8&node=2350149011). -> [!TIP] -> Some settings are available in the **Project Properties** editor in Visual Studio to change values. Right-click on the project in the **Solution Explorer** pane and choose **Properties**. For more information, see [Project configuration in .NET MAUI](../../deployment/visual-studio-properties.md). +Using an established marketplace is the most common way to publish an app as it provides the broadest market reach and the greatest control over distribution. However, publishing an app through a marketplace requires extra effort. -The following table describes how each project setting maps to the manifest file: +Multiple channels can distribute a .NET MAUI app simultaneously. For example, an app could be published on Google Play, the Amazon App Store for Android, and also be downloaded from a web server. -| Project setting | Manifest setting | -| --- | --- | -| `ApplicationId` | The `package` attribute of the `` node: `` node: ``. | +Making your app available for direct download is most useful for a controlled subset of users, such as an enterprise environment or an app that is only meant for a small or well-specified set of users. Server and email distribution are also simpler publishing models, requiring less preparation to publish an app, though apps may be blocked as an email attachment. -Here's an example of an automatically generated manifest file with the package and version information specified: +The Amazon Mobile App Distribution Program enables mobile app developers to distribute and sell their applications on Amazon. Users can discover and shop for apps on their Android devices by using the Amazon App Store application. -```xml - - - -``` +Google Play is arguably the most comprehensive and popular marketplace for Android applications. Google Play allows users to discover, download, rate, and pay for applications by clicking a single icon either on their device or on their computer. Google Play also provides tools to help in the analysis of sales and market trends and to control which devices and users may download an application. -For more information about the manifest, see [Google Android App Manifest Overview](https://developer.android.com/guide/topics/manifest/manifest-intro). - -## Create a keystore file - -Your app package should be signed. You use a keystore file to sign your package. The Java/Android SDKs includes the tools you need to generate a keystore. After generating a keystore file, you'll add it to your project and configure your project file to reference it. The Java SDK should be in your system path so that you can run the _keytool_ tool. - -Perform the following steps to create a keystore file: - -01. Open a terminal and navigate to the folder of your project. - - > [!TIP] - > If Visual Studio is open, use the **View** > **Terminal** menu to open a terminal at the location of the solution or project. Navigate to the project folder. - -01. Run the _keytool_ tool with the following parameters: - - ```console - keytool -genkey -v -keystore myapp.keystore -alias key -keyalg RSA -keysize 2048 -validity 10000 - ``` - - You'll be prompted to provide and confirm a password, followed by other settings. - - The tool generates a _myapp.keystore_ file, which should be located in the same folder as your project. - -## Add a reference to the keystore file - -There are project-level settings you must set to sign your Android app with the keystore file. These settings are configured in a `` node: - -- `` – Set to `True` to sign the app. -- `` – The keystore file created in the previous section: **myapp.keystore**. -- `` – The `-alias` parameter value passed to the _keytool_ tool: **key**. -- `` – The password you provided when creating the keystore file. -- `` – The password you provided when creating the keystore file. - -For security reasons, you don't want to supply a value for `` and `` in the project file. You can provide these values on the command line when you publish the app. An example of providing the password is in the [Publish section](#publish). - -```xml - - True - myapp.keystore - key - - - -``` - -The example `` above adds a condition check, preventing those settings from being processed unless the condition check passes. The condition check looks for two things: - -01. The target framework is set to something containing the text `-android`. -01. The build configuration is set to `Release`. - -If either of those conditions fail, the settings aren't processed. More importantly, the `` setting isn't set, preventing the app from being signed. - -## Publish - -At this time, publishing is only supported through the .NET command line interface. - -To publish your app, open a terminal and navigate to the folder for your .NET MAUI app project. Run the `dotnet publish` command, providing the following parameters: - -| Parameter | Value | -|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------| -| `-f` or `--framework` | The target framework, which is `net6.0-android`. | -| `-c` or `--configuration` | The build configuration, which is `Release`. | -| `/p:AndroidSigningKeyPass` | This is the value used for the `` project setting, the password you provided when you created the keystore file. | -| `/p:AndroidSigningStorePass` | This is the value used for the `` project setting, the password you provided when you created the keystore file. | - -> [!WARNING] -> Attempting to publish a .NET MAUI solution will result in the `dotnet publish` command attempting to publish each project in the solution individually, which can cause issues when you've added other project types to your solution. Therefore, the `dotnet publish` command should be scoped to your .NET MAUI app project. - -For example: +## See also -```console -dotnet publish -f:net6.0-android -c:Release /p:AndroidSigningKeyPass=mypassword /p:AndroidSigningStorePass=mypassword -``` +This section links to articles that may help in publishing an app to an app store such as Google Play. -Publishing builds the app, and then copies the _aab_ and _apk_ files to the _bin\\Release\\net6.0-android\\publish_ folder. There are two _aab_ files, one unsigned and another signed. The signed variant has **-signed** in the file name. + -For more information about the `dotnet publish` command, see [dotnet publish](/dotnet/core/tools/dotnet-publish). +### Google Play app store -To learn how to upload a signed Android App Bundle to the Google Play Store, see [Upload your app to the Play Console](https://developer.android.com/studio/publish/upload-bundle). +- [Publishing on Google Play](https://developer.android.com/distribute/googleplay/publish/index.html) +- [Google Application Licensing](https://developer.android.com/guide/google/play/licensing/index.html) -## See also +### Amazon app store -- [GitHub discussion and feedback: .NET MAUI Android target publishing/archiving](https://github.com/dotnet/maui/issues/4377) -- [Android Developers: About Android App Bundles](https://developer.android.com/guide/app-bundle) -- [Android Developers: Meet Google Play's target API level requirement](https://developer.android.com/google/play/requirements/target-sdk) +- [Mobile App Distribution Portal](https://developer.amazon.com/welcome.html) +- [Amazon Mobile App Distribution FAQ](https://developer.amazon.com/help/faq.html) diff --git a/docs/android/deployment/publish-cli.md b/docs/android/deployment/publish-cli.md new file mode 100644 index 000000000..da56fc221 --- /dev/null +++ b/docs/android/deployment/publish-cli.md @@ -0,0 +1,145 @@ +--- +title: "Use the CLI to publish for Android" +description: "Learn how to package and publish a Android .NET MAUI app with the dotnet publish command." +ms.date: 03/17/2022 +--- + +# Publish a .NET MAUI app for Android with the CLI + +> [!div class="op_single_selector"] +> +> - [Publish for Android](publish-cli.md) +> - [Publish for iOS](../../ios/deployment/overview.md) +> - [Publish for macOS](../../macos/deployment/overview.md) +> - [Publish for Windows](../../windows/deployment/publish-cli.md) + +When distributing your .NET Multi-platform App UI (.NET MAUI) app for Android, you generate an _apk_ (Android Package) or an _aab_ (Android App Bundle) file. The _apk_ is used for installing your app to an Android device, and the _aab_ is used to publish your app to an Android store. + +With just a few configuration changes to your project, your app can be packaged for distribution. + +## Validate package settings + +Every Android app specifies a unique package identifier and a version. These identifiers are generally set in the Android app manifest file, which is located in your project folder at _.\\Platforms\\Android\\AndroidManifest.xml_. However, these specific settings are provided by the project file itself. When a .NET MAUI app is built, the final _AndroidManifest.xml_ file is automatically generated using the project file and the original _AndroidManifest.xml_ file. + +Your project file must declare `` and `` within a `` node. These items should have been generated for you when the project was created. Just validate that they exist and are set to valid values: + +```xml + + + + + + com.companyname.myproject + 1 + + + +``` + +> [!TIP] +> Some settings are available in the **Project Properties** editor in Visual Studio to change values. Right-click on the project in the **Solution Explorer** pane and choose **Properties**. For more information, see [Project configuration in .NET MAUI](../../deployment/visual-studio-properties.md). + +The following table describes how each project setting maps to the manifest file: + +| Project setting | Manifest setting | +| --- | --- | +| `ApplicationId` | The `package` attribute of the `` node: `` node: ``. | + +Here's an example of an automatically generated manifest file with the package and version information specified: + +```xml + + + +``` + +For more information about the manifest, see [Google Android App Manifest Overview](https://developer.android.com/guide/topics/manifest/manifest-intro). + +## Create a keystore file + +Your app package should be signed. You use a keystore file to sign your package. The Java/Android SDKs includes the tools you need to generate a keystore. After generating a keystore file, you'll add it to your project and configure your project file to reference it. The Java SDK should be in your system path so that you can run the _keytool_ tool. + +Perform the following steps to create a keystore file: + +01. Open a terminal and navigate to the folder of your project. + + > [!TIP] + > If Visual Studio is open, use the **View** > **Terminal** menu to open a terminal at the location of the solution or project. Navigate to the project folder. + +01. Run the _keytool_ tool with the following parameters: + + ```console + keytool -genkey -v -keystore myapp.keystore -alias key -keyalg RSA -keysize 2048 -validity 10000 + ``` + + You'll be prompted to provide and confirm a password, followed by other settings. + + The tool generates a _myapp.keystore_ file, which should be located in the same folder as your project. + +## Add a reference to the keystore file + +There are project-level settings you must set to sign your Android app with the keystore file. These settings are configured in a `` node: + +- `` – Set to `True` to sign the app. +- `` – The keystore file created in the previous section: **myapp.keystore**. +- `` – The `-alias` parameter value passed to the _keytool_ tool: **key**. +- `` – The password you provided when creating the keystore file. +- `` – The password you provided when creating the keystore file. + +For security reasons, you don't want to supply a value for `` and `` in the project file. You can provide these values on the command line when you publish the app. An example of providing the password is in the [Publish section](#publish). + +```xml + + True + myapp.keystore + key + + + +``` + +The example `` above adds a condition check, preventing those settings from being processed unless the condition check passes. The condition check looks for two things: + +01. The target framework is set to something containing the text `-android`. +01. The build configuration is set to `Release`. + +If either of those conditions fail, the settings aren't processed. More importantly, the `` setting isn't set, preventing the app from being signed. + +## Publish + +At this time, publishing is only supported through the .NET command line interface. + +To publish your app, open a terminal and navigate to the folder for your .NET MAUI app project. Run the `dotnet publish` command, providing the following parameters: + +| Parameter | Value | +|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------| +| `-f` or `--framework` | The target framework, which is `net6.0-android`. | +| `-c` or `--configuration` | The build configuration, which is `Release`. | +| `/p:AndroidSigningKeyPass` | This is the value used for the `` project setting, the password you provided when you created the keystore file. | +| `/p:AndroidSigningStorePass` | This is the value used for the `` project setting, the password you provided when you created the keystore file. | + +> [!WARNING] +> Attempting to publish a .NET MAUI solution will result in the `dotnet publish` command attempting to publish each project in the solution individually, which can cause issues when you've added other project types to your solution. Therefore, the `dotnet publish` command should be scoped to your .NET MAUI app project. + +For example: + +```console +dotnet publish -f:net6.0-android -c:Release /p:AndroidSigningKeyPass=mypassword /p:AndroidSigningStorePass=mypassword +``` + +Publishing builds the app, and then copies the _aab_ and _apk_ files to the _bin\\Release\\net6.0-android\\publish_ folder. There are two _aab_ files, one unsigned and another signed. The signed variant has **-signed** in the file name. + +For more information about the `dotnet publish` command, see [dotnet publish](/dotnet/core/tools/dotnet-publish). + +To learn how to upload a signed Android App Bundle to the Google Play Store, see [Upload your app to the Play Console](https://developer.android.com/studio/publish/upload-bundle). + +## See also + +- [GitHub discussion and feedback: .NET MAUI Android target publishing/archiving](https://github.com/dotnet/maui/issues/4377) +- [Android Developers: About Android App Bundles](https://developer.android.com/guide/app-bundle) +- [Android Developers: Meet Google Play's target API level requirement](https://developer.android.com/google/play/requirements/target-sdk) diff --git a/docs/android/emulator/troubleshooting.md b/docs/android/emulator/troubleshooting.md index 5cd7acbdb..db46188e6 100644 --- a/docs/android/emulator/troubleshooting.md +++ b/docs/android/emulator/troubleshooting.md @@ -2,7 +2,7 @@ title: "Android Emulator Troubleshooting" description: "This article explains how to diagnose and work around problems that may occur when using the Android Emulator to deploy and run your .NET MAUI app." zone_pivot_groups: platform -ms.date: 02/23/2022 +ms.date: 10/14/2022 --- # Android emulator troubleshooting @@ -85,6 +85,9 @@ When using hardware acceleration, you may run into configuration problems or con This command assumes that the Android SDK is installed at the default location of _C:\\Program Files (x86)\\Android\\android-sdk_. If the Android SDK is installed elsewhere, modify the preceding command to the correct location. +> [!TIP] +> Make sure the Android Emulator is up to date. From Visual Studio, press **Tools** > **Android** > **Android SDK Manager**. Select the **Tools** tab and see if the **Android Emulator** entry has an update available. + ### Hardware acceleration not available If Hyper-V is available, a message like the following example will be returned from the **emulator-check.exe accel** command: diff --git a/docs/fundamentals/app-lifecycle.md b/docs/fundamentals/app-lifecycle.md index 01c67dec8..24fe63663 100644 --- a/docs/fundamentals/app-lifecycle.md +++ b/docs/fundamentals/app-lifecycle.md @@ -1,7 +1,7 @@ --- title: "App lifecycle" description: ".NET MAUI raises cross-platform lifecycle events when an app transitions between its different execution states." -ms.date: 10/04/2022 +ms.date: 10/13/2022 --- # App lifecycle @@ -167,15 +167,16 @@ namespace PlatformLifecycleDemo { #if ANDROID events.AddAndroid(android => android - .OnActivityResult((activity, requestCode, resultCode, data) => LogEvent("OnActivityResult", requestCode.ToString())) - .OnStart((activity) => LogEvent("OnStart")) - .OnCreate((activity, bundle) => LogEvent("OnCreate")) - .OnBackPressed((activity) => LogEvent("OnBackPressed")) - .OnStop((activity) => LogEvent("OnStop"))); + .OnActivityResult((activity, requestCode, resultCode, data) => LogEvent(nameof(AndroidLifecycle.OnActivityResult), requestCode.ToString())) + .OnStart((activity) => LogEvent(nameof(AndroidLifecycle.OnStart))) + .OnCreate((activity, bundle) => LogEvent(nameof(AndroidLifecycle.OnCreate))) + .OnBackPressed((activity) => LogEvent(nameof(AndroidLifecycle.OnBackPressed)) && false) + .OnStop((activity) => LogEvent(nameof(AndroidLifecycle.OnStop)))); #endif - static void LogEvent(string eventName, string type = null) + static bool LogEvent(string eventName, string type = null) { System.Diagnostics.Debug.WriteLine($"Lifecycle event: {eventName}{(type == null ? string.Empty : $" ({type})")}"); + return true; } }); @@ -262,14 +263,15 @@ namespace PlatformLifecycleDemo { #if IOS events.AddiOS(ios => ios - .OnActivated((app) => LogEvent("OnActivated")) - .OnResignActivation((app) => LogEvent("OnResignActivation")) - .DidEnterBackground((app) => LogEvent("DidEnterBackground")) - .WillTerminate((app) => LogEvent("WillTerminate"))); + .OnActivated((app) => LogEvent(nameof(iOSLifecycle.OnActivated))) + .OnResignActivation((app) => LogEvent(nameof(iOSLifecycle.OnResignActivation))) + .DidEnterBackground((app) => LogEvent(nameof(iOSLifecycle.DidEnterBackground))) + .WillTerminate((app) => LogEvent(nameof(iOSLifecycle.WillTerminate)))); #endif - static void LogEvent(string eventName, string type = null) + static bool LogEvent(string eventName, string type = null) { System.Diagnostics.Debug.WriteLine($"Lifecycle event: {eventName}{(type == null ? string.Empty : $" ({type})")}"); + return true; } }); @@ -319,23 +321,24 @@ namespace PlatformLifecycleDemo .ConfigureLifecycleEvents(events => { #if WINDOWS - events.AddWindows(windows => windows - .OnActivated((window, args) => LogEvent("OnActivated")) - .OnClosed((window, args) => LogEvent("OnClosed")) - .OnLaunched((window, args) => LogEvent("OnLaunched")) - .OnLaunching((window, args) => LogEvent("OnLaunching")) - .OnVisibilityChanged((window, args) => LogEvent("OnVisibilityChanged")) - .OnPlatformMessage((window, args) => - { - if (args.MessageId == Convert.ToUInt32("0x031A")) - { - // System theme has changed - } - })); + events.AddWindows(windows => windows + .OnActivated((window, args) => LogEvent(nameof(WindowsLifecycle.OnActivated))) + .OnClosed((window, args) => LogEvent(nameof(WindowsLifecycle.OnClosed))) + .OnLaunched((window, args) => LogEvent(nameof(WindowsLifecycle.OnLaunched))) + .OnLaunching((window, args) => LogEvent(nameof(WindowsLifecycle.OnLaunching))) + .OnVisibilityChanged((window, args) => LogEvent(nameof(WindowsLifecycle.OnVisibilityChanged))) + .OnPlatformMessage((window, args) => + { + if (args.MessageId == Convert.ToUInt32("031A", 16)) + { + // System theme has changed + } + })); #endif - static void LogEvent(string eventName, string type = null) + static bool LogEvent(string eventName, string type = null) { System.Diagnostics.Debug.WriteLine($"Lifecycle event: {eventName}{(type == null ? string.Empty : $" ({type})")}"); + return true; } }); @@ -462,9 +465,10 @@ The WinUI 3 LogEvent("Window SizeChanged")); #endif - static void LogEvent(string eventName, string type = null) + static bool LogEvent(string eventName, string type = null) { System.Diagnostics.Debug.WriteLine($"Lifecycle event: {eventName}{(type == null ? string.Empty : $" ({type})")}"); + return true; } }); diff --git a/docs/platform-integration/device/geolocation.md b/docs/platform-integration/device/geolocation.md index ce64ace1c..11789c224 100644 --- a/docs/platform-integration/device/geolocation.md +++ b/docs/platform-integration/device/geolocation.md @@ -137,6 +137,9 @@ The following code example demonstrates how to request the device's location, wh Not all location values may be available, depending on the device. For example, the `Altitude` property might be `null`, have a value of 0, or have a positive value indicating the meters above sea level. Other values that may not be present include `Speed` and `Course`. +> [!WARNING] +> `GetLocationAsync` can return `null` in some scenarios. This indicates that the underlying platform is unable to obtain the current location. + ## Accuracy The following sections outline the location accuracy distance, per platform: diff --git a/docs/user-interface/controls/graphicsview.md b/docs/user-interface/controls/graphicsview.md index 0a0c9bfa5..46ffe9572 100644 --- a/docs/user-interface/controls/graphicsview.md +++ b/docs/user-interface/controls/graphicsview.md @@ -66,7 +66,7 @@ The location and size of the `ICanvas` on a page can be determined by examining The `RectF` struct defines the following properties: - `Bottom`, of type `float`, which represents the y-coordinate of the bottom edge of the canvas. -- `Center`, of type `PointF`. which specifies the coordinates of the center of the canvas. +- `Center`, of type `PointF`, which specifies the coordinates of the center of the canvas. - `Height`, of type `float`, which defines the height of the canvas. - `IsEmpty`, of type `bool`, which indicates whether the canvas has a zero size and location. - `Left`, of type `float`, which represents the x-coordinate of the left edge of the canvas. diff --git a/docs/user-interface/controls/image.md b/docs/user-interface/controls/image.md index 55cf12e51..268de25be 100644 --- a/docs/user-interface/controls/image.md +++ b/docs/user-interface/controls/image.md @@ -106,7 +106,7 @@ To set a specific cache period, set the `Source` property to an `UriImageSource` + CacheValidity="10:00:00" /> ``` diff --git a/docs/user-interface/controls/media/twopaneview/emulator-foldable-maui-app.png b/docs/user-interface/controls/media/twopaneview/emulator-foldable-maui-app.png new file mode 100644 index 000000000..04579c51c Binary files /dev/null and b/docs/user-interface/controls/media/twopaneview/emulator-foldable-maui-app.png differ diff --git a/docs/user-interface/controls/media/twopaneview/foldable-maui-app.png b/docs/user-interface/controls/media/twopaneview/foldable-maui-app.png new file mode 100644 index 000000000..d21e0000f Binary files /dev/null and b/docs/user-interface/controls/media/twopaneview/foldable-maui-app.png differ diff --git a/docs/user-interface/controls/shapes/geometries.md b/docs/user-interface/controls/shapes/geometries.md index 38ced0768..b3a6773b2 100644 --- a/docs/user-interface/controls/shapes/geometries.md +++ b/docs/user-interface/controls/shapes/geometries.md @@ -184,8 +184,8 @@ These properties are backed by `BindableProperty` objects, which means that they The `SweepDirection` enumeration defines the following members: -- `CounterClockwise`, which specifies that arcs are drawn in a clockwise direction. -- `Clockwise`, which specifies that arcs are drawn in a counter clockwise direction. +- `CounterClockwise`, which specifies that arcs are drawn in a counter clockwise direction. +- `Clockwise`, which specifies that arcs are drawn in a clockwise direction. The following example shows how to create and render an `ArcSegment` in a `Path` object: @@ -533,7 +533,7 @@ Composite geometry objects can be created using a `GeometryGroup`. The `Geometry The `GeometryGroup` class defines the following properties: -- `Children`, of type `GeometryCollection`, which species the objects that define the `GeomtryGroup`. A `GeometryCollection` is an `ObservableCollection` of `Geometry` objects. +- `Children`, of type `GeometryCollection`, which specifies the objects that define the `GeomtryGroup`. A `GeometryCollection` is an `ObservableCollection` of `Geometry` objects. - `FillRule`, of type `FillRule`, which specifies how the intersecting areas in the `GeometryGroup` are combined. The default value of this property is `FillRule.EvenOdd`. These properties are backed by `BindableProperty` objects, which means that they can be targets of data bindings, and styled. diff --git a/docs/user-interface/controls/shapes/index.md b/docs/user-interface/controls/shapes/index.md index e244e7c23..f41f65769 100644 --- a/docs/user-interface/controls/shapes/index.md +++ b/docs/user-interface/controls/shapes/index.md @@ -85,7 +85,7 @@ In this example, a `Path` object draws a heart. The `Path` object's `WidthReques `Shape` objects have a `StrokeDashArray` property, of type `DoubleCollection`. This property represents a collection of `double` values that indicate the pattern of dashes and gaps that are used to outline a shape. A `DoubleCollection` is an `ObservableCollection` of `double` values. Each `double` in the collection specifies the length of a dash or gap. The first item in the collection, which is located at index 0, specifies the length of a dash. The second item in the collection, which is located at index 1, specifies the length of a gap. Therefore, objects with an even index value specify dashes, while objects with an odd index value specify gaps. -`Shape` objects also have a `StrokeDashOffset` property , of type `double`, which specifies the distance within the dash pattern where a dash begins. Failure to set this property will result in the `Shape` having a solid outline. +`Shape` objects also have a `StrokeDashOffset` property, of type `double`, which specifies the distance within the dash pattern where a dash begins. Failure to set this property will result in the `Shape` having a solid outline. Dashed shapes can be drawn by setting both the `StrokeDashArray` and `StrokeDashOffset` properties. The `StrokeDashArray` property should be set to one or more `double` values, with each pair delimited by a single comma and/or one or more spaces. For example, "0.5 1.0" and "0.5,1.0" are both valid. diff --git a/docs/user-interface/controls/shapes/path-markup-syntax.md b/docs/user-interface/controls/shapes/path-markup-syntax.md index b685efd1d..fc5535e0a 100644 --- a/docs/user-interface/controls/shapes/path-markup-syntax.md +++ b/docs/user-interface/controls/shapes/path-markup-syntax.md @@ -104,7 +104,7 @@ For information about creating an elliptical arc as a `PathGeometry` object, see ### Cubic Bezier curve command -The cubic Bezier curve command creates a cubic Bezier curve between the current point and the specified end point by using the two specified control point. The syntax for this command is: `C` *controlPoint1* *controlPoint2* *endPoint* or `c` *controlPoint1* *controlPoint2* *endPoint*. +The cubic Bezier curve command creates a cubic Bezier curve between the current point and the specified end point by using the two specified control points. The syntax for this command is: `C` *controlPoint1* *controlPoint2* *endPoint* or `c` *controlPoint1* *controlPoint2* *endPoint*. In this syntax: @@ -163,7 +163,7 @@ The syntax for the close command is: `Z` or `z`. Instead of a standard numerical value, you can also use the following case-sensitive special values: - `Infinity` represents `double.PositiveInfinity`. -- `-Infinity`represents `double.NegativeInfinity`. +- `-Infinity` represents `double.NegativeInfinity`. - `NaN` represents `double.NaN`. In addition, you may also use case-insensitive scientific notation. Therefore, `+1.e17` is a valid value. diff --git a/docs/user-interface/controls/twopaneview.md b/docs/user-interface/controls/twopaneview.md new file mode 100644 index 000000000..1c8b9966c --- /dev/null +++ b/docs/user-interface/controls/twopaneview.md @@ -0,0 +1,120 @@ +--- +title: "TwoPaneView foldable and large-screen layout control" +description: "Learn how to use the TwoPaneView control to create adaptive layouts that work on phones, tablets, desktop, and foldable devices." +monikerRange: ">= net-maui-7.0" +author: conceptdev +ms.author: crdun +ms.date: 11/03/2022 +--- +# .NET MAUI TwoPaneView layout + +[![Browse sample.](~/media/code-sample.png) Browse the sample](https://github.com/conceptdev/dotnet-maui-samples/) + +The `TwoPaneView` class represents a container with two views that size and position content in the available space, either side-by-side or top-to-bottom. `TwoPaneView` inherits from `Grid` so the easiest way to think about these properties is as if they are being applied to a grid. + +:::image type="content" source="media/twopaneview/foldable-maui-app.png" alt-text="Surface Duo dual-screen emulator showing a basic TwoPaneView test app"::: + +The layout control is provided by the [Microsoft.Maui.Controls.Foldable NuGet package](https://www.nuget.org/packages/Microsoft.Maui.Controls.Foldable/). + +## Foldable device support overview + +Foldable devices include the Microsoft Surface Duo and Android devices from other manufacturers. They bridge the gap between phones and larger screens like tablets and desktops because apps might need to adjust to a variety of screen sizes and orientations on the same device, including adapting to a hinge or fold in the screen. + +Visit the [dual-screen developer docs](/dual-screen/) for more information about building apps that target foldable devices, including [design patterns and user experiences](/dual-screen/design/). There is also a [Surface Duo emulator](/dual-screen/android/emulator/) you can download for Windows, Mac, and Linux. + +> [!IMPORTANT] +> The `TwoPaneView` control only adapts to Android foldable devices that support the Jetpack Window Manager API provided by Google (such as Microsoft Surface Duo). +> +> On all other platforms and devices (i.e. other Android devices, iOS, macOS, Windows) it acts like a configurable and responsive split view that can dynamically show one or two panes, proportionally sized on the screen. + +## Add and configure the Foldable support NuGet + +1. Open the **NuGet Package Manager** dialog for your solution. +2. Under the **Browse** tab, search for `Microsoft.Maui.Controls.Foldable`. +3. Install the `Microsoft.Maui.Controls.Foldable` package to your solution. +4. Add the `UseFoldable()` initialization method (and namespace) call to the project's `MauiApp` class, in the `CreateMauiApp` method: + + ```csharp + using Microsoft.Maui.Foldable; // ADD THIS NAMESPACE + ... + public static MauiApp CreateMauiApp() + { + var builder = MauiApp.CreateBuilder(); + ... + builder.UseFoldable(); // ADD THIS LINE TO THE TEMPLATE + return builder.Build(); + } + ``` + + The `UseFoldable()` initialization is required for the app to be able to detect changes in the app's state, such as being spanned across a fold. + +5. Update the `[Activity(...)]` attribute on the `MainActivity` class in **Platforms/Android**, so that it includes _all_ these `ConfigurationChanges` options: + + ```csharp + ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize + | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.UiMode + ``` + + These values are required so that configuration changes and span state can be more reliably reported for reliable dual-screen support. + +## Set up TwoPaneView + +To add the TwoPaneView layout to your page: + +1. Add a `foldable` namespace alias for the Foldable NuGet: + + ```xaml + xmlns:foldable="clr-namespace:Microsoft.Maui.Controls.Foldable;assembly=Microsoft.Maui.Controls.Foldable" + ``` + +2. Add the `TwoPaneView` as the root element on the page, and add controls to `Pane1` and `Pane2`: + + ```xaml + + + + + + + + + ``` + +## Understand TwoPaneView modes + +Only one of these modes can be active: + +- `SinglePane` only one pane is currently visible. +- `Wide` the two panes are laid out horizontally. One pane is on the left and the other is on the right. When on two screens this is the mode when the device is portrait. +- `Tall` the two panes are laid out vertically. One pane is on top and the other is on bottom. When on two screens this is the mode when the device is landscape. + +### Control TwoPaneView when it's only on one screen + +The following properties apply when the `TwoPaneView` is occupying a single screen: + +- `MinTallModeHeight` indicates the minimum height the control must be to enter tall mode. +- `MinWideModeWidth` indicates the minimum width the control must be to enter wide mode. +- `Pane1Length` sets the width of Pane1 in Wide mode, the height of Pane1 in Tall mode, and has no effect in SinglePane mode. +- `Pane2Length` sets the width of Pane2 in Wide mode, the height of Pane2 in Tall mode, and has no effect in SinglePane mode. + +> [!IMPORTANT] +> If the `TwoPaneView` is spanned across a hinge or fold these properties have no effect. + +### Properties that apply when on one screen or two + +The following properties apply when the `TwoPaneView` is occupying a single screen or two screens: + +- `TallModeConfiguration` indicates, when in tall mode, the Top/Bottom arrangement or if you only want a single pane visible as defined by the TwoPaneViewPriority. +- `WideModeConfiguration` indicates, when in wide mode, the Left/Right arrangement or if you only want a single pane visible as defined by the TwoPaneViewPriority. +- `PanePriority` determines whether to show Pane1 or Pane2 if in SinglePane mode. + +## Troubleshooting + +If the `TwoPaneView` layout isn't working as expected, double-check the set-up instructions on this page. Omitting or misconfiguring the `UseFoldable()` method or the `ConfigurationChanges` attribute values are common causes of errors. diff --git a/docs/windows/deployment/media/overview/certificate-import-success.png b/docs/windows/deployment/media/publish-cli/certificate-import-success.png similarity index 100% rename from docs/windows/deployment/media/overview/certificate-import-success.png rename to docs/windows/deployment/media/publish-cli/certificate-import-success.png diff --git a/docs/windows/deployment/media/overview/certificate-import.pdn b/docs/windows/deployment/media/publish-cli/certificate-import.pdn similarity index 100% rename from docs/windows/deployment/media/overview/certificate-import.pdn rename to docs/windows/deployment/media/publish-cli/certificate-import.pdn diff --git a/docs/windows/deployment/media/overview/certificate-import.png b/docs/windows/deployment/media/publish-cli/certificate-import.png similarity index 100% rename from docs/windows/deployment/media/overview/certificate-import.png rename to docs/windows/deployment/media/publish-cli/certificate-import.png diff --git a/docs/windows/deployment/media/overview/install-trusted.png b/docs/windows/deployment/media/publish-cli/install-trusted.png similarity index 100% rename from docs/windows/deployment/media/overview/install-trusted.png rename to docs/windows/deployment/media/publish-cli/install-trusted.png diff --git a/docs/windows/deployment/media/overview/install-untrusted.png b/docs/windows/deployment/media/publish-cli/install-untrusted.png similarity index 100% rename from docs/windows/deployment/media/overview/install-untrusted.png rename to docs/windows/deployment/media/publish-cli/install-untrusted.png diff --git a/docs/windows/deployment/media/overview/properties-digital-signatures.pdn b/docs/windows/deployment/media/publish-cli/properties-digital-signatures.pdn similarity index 100% rename from docs/windows/deployment/media/overview/properties-digital-signatures.pdn rename to docs/windows/deployment/media/publish-cli/properties-digital-signatures.pdn diff --git a/docs/windows/deployment/media/overview/properties-digital-signatures.png b/docs/windows/deployment/media/publish-cli/properties-digital-signatures.png similarity index 100% rename from docs/windows/deployment/media/overview/properties-digital-signatures.png rename to docs/windows/deployment/media/publish-cli/properties-digital-signatures.png diff --git a/docs/windows/deployment/media/publish-visual-studio/solution-exporer-manifest-files.png b/docs/windows/deployment/media/publish-visual-studio/solution-exporer-manifest-files.png new file mode 100644 index 000000000..5a7ced8c6 Binary files /dev/null and b/docs/windows/deployment/media/publish-visual-studio/solution-exporer-manifest-files.png differ diff --git a/docs/windows/deployment/media/publish-visual-studio/vs-1-how-distribute.pdn b/docs/windows/deployment/media/publish-visual-studio/vs-1-how-distribute.pdn new file mode 100644 index 000000000..145403717 Binary files /dev/null and b/docs/windows/deployment/media/publish-visual-studio/vs-1-how-distribute.pdn differ diff --git a/docs/windows/deployment/media/publish-visual-studio/vs-1-how-distribute.png b/docs/windows/deployment/media/publish-visual-studio/vs-1-how-distribute.png new file mode 100644 index 000000000..a6ebbd499 Binary files /dev/null and b/docs/windows/deployment/media/publish-visual-studio/vs-1-how-distribute.png differ diff --git a/docs/windows/deployment/media/publish-visual-studio/vs-2-cert-sign.pdn b/docs/windows/deployment/media/publish-visual-studio/vs-2-cert-sign.pdn new file mode 100644 index 000000000..0c6f097e2 Binary files /dev/null and b/docs/windows/deployment/media/publish-visual-studio/vs-2-cert-sign.pdn differ diff --git a/docs/windows/deployment/media/publish-visual-studio/vs-2-cert-sign.png b/docs/windows/deployment/media/publish-visual-studio/vs-2-cert-sign.png new file mode 100644 index 000000000..f1de4d694 Binary files /dev/null and b/docs/windows/deployment/media/publish-visual-studio/vs-2-cert-sign.png differ diff --git a/docs/windows/deployment/media/publish-visual-studio/vs-2_1-create-cert.png b/docs/windows/deployment/media/publish-visual-studio/vs-2_1-create-cert.png new file mode 100644 index 000000000..c9aedfdb2 Binary files /dev/null and b/docs/windows/deployment/media/publish-visual-studio/vs-2_1-create-cert.png differ diff --git a/docs/windows/deployment/media/publish-visual-studio/vs-4-configure.png b/docs/windows/deployment/media/publish-visual-studio/vs-4-configure.png new file mode 100644 index 000000000..fb0ff6229 Binary files /dev/null and b/docs/windows/deployment/media/publish-visual-studio/vs-4-configure.png differ diff --git a/docs/windows/deployment/media/publish-visual-studio/vs-4_1-publish-profile.png b/docs/windows/deployment/media/publish-visual-studio/vs-4_1-publish-profile.png new file mode 100644 index 000000000..2cd94deec Binary files /dev/null and b/docs/windows/deployment/media/publish-visual-studio/vs-4_1-publish-profile.png differ diff --git a/docs/windows/deployment/media/publish-visual-studio/vs-5-configure-done.png b/docs/windows/deployment/media/publish-visual-studio/vs-5-configure-done.png new file mode 100644 index 000000000..6474ed2cd Binary files /dev/null and b/docs/windows/deployment/media/publish-visual-studio/vs-5-configure-done.png differ diff --git a/docs/windows/deployment/media/publish-visual-studio/vs-6-update.png b/docs/windows/deployment/media/publish-visual-studio/vs-6-update.png new file mode 100644 index 000000000..b45dde1f5 Binary files /dev/null and b/docs/windows/deployment/media/publish-visual-studio/vs-6-update.png differ diff --git a/docs/windows/deployment/media/publish-visual-studio/vs-7-complete.png b/docs/windows/deployment/media/publish-visual-studio/vs-7-complete.png new file mode 100644 index 000000000..25a841695 Binary files /dev/null and b/docs/windows/deployment/media/publish-visual-studio/vs-7-complete.png differ diff --git a/docs/windows/deployment/media/publish-visual-studio/vs-debugtarget.pdn b/docs/windows/deployment/media/publish-visual-studio/vs-debugtarget.pdn new file mode 100644 index 000000000..417c24a16 Binary files /dev/null and b/docs/windows/deployment/media/publish-visual-studio/vs-debugtarget.pdn differ diff --git a/docs/windows/deployment/media/publish-visual-studio/vs-debugtarget.png b/docs/windows/deployment/media/publish-visual-studio/vs-debugtarget.png new file mode 100644 index 000000000..1e1b54d67 Binary files /dev/null and b/docs/windows/deployment/media/publish-visual-studio/vs-debugtarget.png differ diff --git a/docs/windows/deployment/media/publish-visual-studio/vs-right-click-publish.pdn b/docs/windows/deployment/media/publish-visual-studio/vs-right-click-publish.pdn new file mode 100644 index 000000000..5a53c25be Binary files /dev/null and b/docs/windows/deployment/media/publish-visual-studio/vs-right-click-publish.pdn differ diff --git a/docs/windows/deployment/media/publish-visual-studio/vs-right-click-publish.png b/docs/windows/deployment/media/publish-visual-studio/vs-right-click-publish.png new file mode 100644 index 000000000..5b5f55a8d Binary files /dev/null and b/docs/windows/deployment/media/publish-visual-studio/vs-right-click-publish.png differ diff --git a/docs/windows/deployment/overview.md b/docs/windows/deployment/overview.md index 092c29894..f9139e5c9 100644 --- a/docs/windows/deployment/overview.md +++ b/docs/windows/deployment/overview.md @@ -1,7 +1,7 @@ --- title: "Publish a .NET MAUI app for Windows" description: "Learn how to package and publish a Windows .NET MAUI app." -ms.date: 05/12/2022 +ms.date: 10/12/2022 --- # Publish a .NET MAUI app for Windows @@ -13,167 +13,28 @@ ms.date: 05/12/2022 > - [Publish for macOS](../../macos/deployment/overview.md) > - [Publish for Windows](overview.md) -When distributing your .NET Multi-platform App UI (.NET MAUI) app for Windows, you can publish the app and its dependencies to a folder for deployment to another system. You can also package the app into an MSIX package, which has numerous benefits for the users installing your app. For more information about the benefits of MSIX, see [What is MSIX?](/windows/msix/overview) +When distributing your .NET Multi-platform App UI (.NET MAUI) app for Windows, you can publish the app and its dependencies to a folder for deployment to another system. Publishing a .NET MAUI app for Windows creates an MSIX app package, which has numerous benefits for the users installing your app. For more information about the benefits of MSIX, see [What is MSIX?](/windows/msix/overview). .NET MAUI currently only allows publishing an MSIX package. You can't yet publish a Windows executable file for distribution. -## Create a signing certificate +## Configuration -You must use a signing certificate for use in publishing your app. This certificate is used to sign the MSIX package. The following steps demonstrate how to create and install a self-signed certificate with PowerShell: +The MSIX package is configured by the _Platforms\\Windows\\Package.appxmanifest_ (the manifest) file in your project. The manifest is used by the MSIX installer, the Microsoft store, and by Windows, to configure and display your app. .NET MAUI does use some shared settings across platforms, such as the app name and icon, which is set in the manifest at build-time. Besides those few settings, you'll need to edit the manifest to configure the app package to create a nice installer experience. The Microsoft Store has its own requirements, set in the manifest, when submitting your app. -> [!NOTE] -> When you create and use a self-signed certificate only users who install and trust your certificate can run your app. This is easy to implement for testing but it may prevent additional users from installing your app. When you are ready to publish your app we recommend that you use a certificate issued by a trusted source. This system of centralized trust helps to ensure that the app ecosystem has levels of verification to protect users from malicious actors. +You can use the Manifest Designer feature of Visual Studio to visually edit the _Package.appxmanifest_ file, which affects how the app is displayed in the Microsoft Store and in Windows. You can also edit the _Package.appxmanifest_ file using the XML editor. -01. Open a PowerShell terminal and navigate to the directory with your project. -01. Use the [`New-SelfSignedCertificate`](/powershell/module/pki/new-selfsignedcertificate?view=windowsserver2019-ps&preserve-view=true) command to generate a self-signed certificate. +- To use the Manifest Designer, find the **Solution Explorer** pane, then right-click **Platforms\\Windows\\Package.appxmanifest** > **Properties**. +- To use the XML editor, find the **Solution Explorer** pane, then right-click **Platforms\\Windows\\Package.appxmanifest** > **View Code**. - The `` value is displayed to the user when they install your app, supply your own value and omit the `< >` characters. You can set the `FriendlyName` parameter to any string of text you want. +> [!IMPORTANT] +> The Manifest Designer for .NET MAUI projects can't edit app capabilities. For the time being, you'll need to use the XML editor. - ```powershell - New-SelfSignedCertificate -Type Custom ` - -Subject "CN=" ` - -KeyUsage DigitalSignature ` - -FriendlyName "My temp dev cert" ` - -CertStoreLocation "Cert:\CurrentUser\My" ` - -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.3", "2.5.29.19={text}") - ``` +For more information on specific app manifest settings, see [App manifest schema reference](/uwp/schemas/appxpackage/uapmanifestschema/root-elements). -01. Use the following PowerShell command to query the certificate store for the certificate that was created: +## Publish your app - ```powershell - Get-ChildItem "Cert:\CurrentUser\My" | Format-Table Subject, FriendlyName, Thumbprint - ``` +.NET MAUI can use Visual Studio for publishing, but also supports publishing through the `dotnet` command-line interface (CLI) for Continuous Integration (CI) scenarios. - You should see results similar to the following output: - - ```text - Thumbprint Subject FriendlyName - ---------- ------- ------------ - DE8B962E7BF797CB48CCF66C8BCACE65C6585E2F CN=1f23fa36-2a2f-475e-a69e-3a14fe56ed4 - A6CA34FD0BA6B439787391F51C87B1AD0C9E7FAE CN=someone@microsoft.com - 94D93DBC97D4F7E4364A215F15C6ACFEFC71E569 CN=localhost ASP.NET Core HTTPS development certificate - F14211566DACE867DA0BF9C2F9C47C01E3CF1D9B CN=john - 568027317BE8EE5E6AACDE5079D2DE76EC46EB88 CN=e1f823e2-4674-03d2-aaad-21ab23ad84ae - DC602EE83C95FEDF280835980E22306067EFCA96 CN=John Smith, OU=MSE, OU=Users, DC=com - 07AD38F3B646F5AAC16F2F2570CAE40F4842BBE0 CN=Contoso My temp dev cert - ``` - -01. The **Thumbprint** of your certificate will be used later, copy it to your clipboard. It's the **Thumbprint** value whose entry matches the **Subject** and **FriendlyName** of your certificate. - -For more information, see [Create a certificate for package signing](/windows/msix/package/create-certificate-package-signing). - - - - -## Configure the project build settings - -The project file is a good place to put Windows-specific build settings. You may not want to put some settings into the project file, such as passwords. The settings described in this section can be passed on the command line with the `/p:name=value` format. If the setting is already defined in the project file, a setting passed on the command line will override the project setting. - -Add the following `` node to your project file. This property group is only processed when the target framework is Windows and the configuration is set to `Release`. This config section runs whenever a build or publish in `Release` mode. - -```xml - - true - A10612AF095FD8F8255F4C6691D88F79EF2B135E - - - $(RuntimeIdentifierOverride) - -``` - - - -Replace the `` property value with the certificate thumbprint you previously generated. Alternatively, you can remove this setting from the project file and provide it on the command line. For example: `/p:PackageCertificateThumbprint=A10612AF095FD8F8255F4C6691D88F79EF2B135E`. - -The second `` in the example is required to work around a bug in the Windows SDK. For more information about the bug, see [WindowsAppSDK Issue #2940](https://github.com/microsoft/WindowsAppSDK/issues/2940). - -## Publish - -To publish your app, open the **Developer Command Prompt for VS 2022** terminal and navigate to the folder for your .NET MAUI app project. Run the `dotnet publish` command, providing the following parameters: - -| Parameter | Value | -|------------------------------|-------------------------------------------------------------------------------------| -| `-f net6.0-windows{version}` | The target framework, which is a Windows TFM, such as `net6.0-windows10.0.19041.0`. Ensure that this value is identical to the value in the `` node in your *.csproj* file. | -| `-c Release` | Sets the build configuration, which is `Release`. | -| `/p:RuntimeIdentifierOverride=win10-x64`
- or -
`/p:RuntimeIdentifierOverride=win10-x86` | Avoids the bug detailed in [WindowsAppSDK Issue #2940](https://github.com/microsoft/WindowsAppSDK/issues/2940). Choose the `-x64` or `-x86` version of the parameter based on your target platform. - -> [!WARNING] -> Attempting to publish a .NET MAUI solution will result in the `dotnet publish` command attempting to publish each project in the solution individually, which can cause issues when you've added other project types to your solution. Therefore, the `dotnet publish` command should be scoped to your .NET MAUI app project. - -For example: - -```console -dotnet publish -f net6.0-windows10.0.19041.0 -c Release /p:RuntimeIdentifierOverride=win10-x64 -``` - -Publishing builds and packages the app, copying the signed package to the _bin\\Release\\net6.0-windows10.0.19041.0\\win10-x64\\AppPackages\\\\\_ folder. \ is a folder named after both your project and version. In this folder, there's an _msix_ file, and that's the app package. - -For more information about the `dotnet publish` command, see [dotnet publish](/dotnet/core/tools/dotnet-publish). - -## Installing the app - -To install the app, it must be signed with a certificate that you already trust. If it isn't, Windows won't let you install the app. You'll be presented with a dialog similar to the following, with the Install button disabled: - -:::image type="content" source="media/overview/install-untrusted.png" alt-text="Installing an untrusted app."::: - -Notice that in the previous image, the Publisher was "unknown." - -To trust the certificate of app package, perform the following steps: - -01. Right-click on the _.msix_ file and choose **Properties**. -01. Select the **Digital Signatures** tab. -01. Choose the certificate then press **Details**. - - :::image type="content" source="media/overview/properties-digital-signatures.png" alt-text="Properties pane of an MSIX file with the digital signatures tab selected."::: - -01. Select **View Certificate**. -01. Select **Install Certificate...** -01. Choose **Local Machine** then select **Next**. - - If you're prompted by User Account Control to **Do you want to allow this app to make changes to your device?**, select **Yes**. - -01. In the **Certificate Import Wizard** window, select **Place all certificates in the following store**. -01. Select **Browse...** and then choose the **Trusted People** store. Select **OK** to close the dialog. - - :::image type="content" source="media/overview/certificate-import.png" alt-text="Certificate import wizard window is shown while selecting the Trusted People store."::: - -01. Select **Next** and then **Finish**. You should see a dialog that says: **The import was successful**. - - :::image type="content" source="media/overview/certificate-import-success.png" alt-text="Certificate import wizard window with a successful import message."::: - -01. Select **OK** on any window opened as part of this process, to close them all. - -Now, try opening the package file again to install the app. You should see a dialog similar to the following, with the Publisher correctly displayed: - -:::image type="content" source="media/overview/install-trusted.png" alt-text="Installing a trusted app."::: - -Select the **Install** button if you would like to install the app. - -## Current limitations - -The following list describes the current limitations with publishing and packaging: - -01. The published app doesn't work if you try to run it directly with the executable file out of the publish folder. -01. The way to run the app is to first install it through the packaged _MSIX_ file. - -## See also - -- [GitHub discussion and feedback: .NET MAUI Windows target publishing/archiving](https://github.com/dotnet/maui/issues/4329) + +- [Publish to a folder with Visual Studio](publish-visual-studio-folder.md) +- [Publish to a folder with the CLI](publish-cli.md) diff --git a/docs/windows/deployment/publish-cli.md b/docs/windows/deployment/publish-cli.md new file mode 100644 index 000000000..3774511f8 --- /dev/null +++ b/docs/windows/deployment/publish-cli.md @@ -0,0 +1,175 @@ +--- +title: "Use the CLI to publish for Windows" +description: "Learn how to package and publish a Windows .NET MAUI app with the dotnet publish command." +ms.date: 10/12/2022 +--- + +# Publish a .NET MAUI app for Windows with the CLI + +> [!div class="op_single_selector"] +> +> - [Publish for Android](../../android/deployment/publish-cli.md) +> - [Publish for iOS](../../ios/deployment/overview.md) +> - [Publish for macOS](../../macos/deployment/overview.md) +> - [Publish for Windows](publish-cli.md) + +When distributing your .NET Multi-platform App UI (.NET MAUI) app for Windows, you can publish the app and its dependencies to a folder for deployment to another system. You can also package the app into an MSIX package, which has numerous benefits for the users installing your app. For more information about the benefits of MSIX, see [What is MSIX?](/windows/msix/overview) + +.NET MAUI currently only allows publishing an MSIX package. You can't yet publish a Windows executable file for distribution. + +## Create a signing certificate + +You must use a signing certificate for use in publishing your app. This certificate is used to sign the MSIX package. The following steps demonstrate how to create and install a self-signed certificate with PowerShell: + +> [!NOTE] +> When you create and use a self-signed certificate only users who install and trust your certificate can run your app. This is easy to implement for testing but it may prevent additional users from installing your app. When you are ready to publish your app we recommend that you use a certificate issued by a trusted source. This system of centralized trust helps to ensure that the app ecosystem has levels of verification to protect users from malicious actors. + +01. Open a PowerShell terminal and navigate to the directory with your project. +01. Use the [`New-SelfSignedCertificate`](/powershell/module/pki/new-selfsignedcertificate?view=windowsserver2019-ps&preserve-view=true) command to generate a self-signed certificate. + + The `` value is displayed to the user when they install your app, supply your own value and omit the `< >` characters. You can set the `FriendlyName` parameter to any string of text you want. + + ```powershell + New-SelfSignedCertificate -Type Custom ` + -Subject "CN=" ` + -KeyUsage DigitalSignature ` + -FriendlyName "My temp dev cert" ` + -CertStoreLocation "Cert:\CurrentUser\My" ` + -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.3", "2.5.29.19={text}") + ``` + +01. Use the following PowerShell command to query the certificate store for the certificate that was created: + + ```powershell + Get-ChildItem "Cert:\CurrentUser\My" | Format-Table Subject, FriendlyName, Thumbprint + ``` + + You should see results similar to the following output: + + ```text + Thumbprint Subject FriendlyName + ---------- ------- ------------ + DE8B962E7BF797CB48CCF66C8BCACE65C6585E2F CN=1f23fa36-2a2f-475e-a69e-3a14fe56ed4 + A6CA34FD0BA6B439787391F51C87B1AD0C9E7FAE CN=someone@microsoft.com + 94D93DBC97D4F7E4364A215F15C6ACFEFC71E569 CN=localhost ASP.NET Core HTTPS development certificate + F14211566DACE867DA0BF9C2F9C47C01E3CF1D9B CN=john + 568027317BE8EE5E6AACDE5079D2DE76EC46EB88 CN=e1f823e2-4674-03d2-aaad-21ab23ad84ae + DC602EE83C95FEDF280835980E22306067EFCA96 CN=John Smith, OU=MSE, OU=Users, DC=com + 07AD38F3B646F5AAC16F2F2570CAE40F4842BBE0 CN=Contoso My temp dev cert + ``` + +01. The **Thumbprint** of your certificate will be used later, copy it to your clipboard. It's the **Thumbprint** value whose entry matches the **Subject** and **FriendlyName** of your certificate. + +For more information, see [Create a certificate for package signing](/windows/msix/package/create-certificate-package-signing). + + + + +## Configure the project build settings + +The project file is a good place to put Windows-specific build settings. You may not want to put some settings into the project file, such as passwords. The settings described in this section can be passed on the command line with the `/p:name=value` format. If the setting is already defined in the project file, a setting passed on the command line will override the project setting. + +Add the following `` node to your project file. This property group is only processed when the target framework is Windows and the configuration is set to `Release`. This config section runs whenever a build or publish in `Release` mode. + +```xml + + true + A10612AF095FD8F8255F4C6691D88F79EF2B135E + + + $(RuntimeIdentifierOverride) + +``` + + + +Replace the `` property value with the certificate thumbprint you previously generated. Alternatively, you can remove this setting from the project file and provide it on the command line. For example: `/p:PackageCertificateThumbprint=A10612AF095FD8F8255F4C6691D88F79EF2B135E`. + +The second `` in the example is required to work around a bug in the Windows SDK. For more information about the bug, see [WindowsAppSDK Issue #2940](https://github.com/microsoft/WindowsAppSDK/issues/2940). + +## Publish + +To publish your app, open the **Developer Command Prompt for VS 2022** terminal and navigate to the folder for your .NET MAUI app project. Run the `dotnet publish` command, providing the following parameters: + +| Parameter | Value | +|------------------------------|-------------------------------------------------------------------------------------| +| `-f net6.0-windows{version}` | The target framework, which is a Windows TFM, such as `net6.0-windows10.0.19041.0`. Ensure that this value is identical to the value in the `` node in your *.csproj* file. | +| `-c Release` | Sets the build configuration, which is `Release`. | +| `/p:RuntimeIdentifierOverride=win10-x64`
- or -
`/p:RuntimeIdentifierOverride=win10-x86` | Avoids the bug detailed in [WindowsAppSDK Issue #2940](https://github.com/microsoft/WindowsAppSDK/issues/2940). Choose the `-x64` or `-x86` version of the parameter based on your target platform. + +> [!WARNING] +> Attempting to publish a .NET MAUI solution will result in the `dotnet publish` command attempting to publish each project in the solution individually, which can cause issues when you've added other project types to your solution. Therefore, the `dotnet publish` command should be scoped to your .NET MAUI app project. + +For example: + +```console +dotnet publish -f net6.0-windows10.0.19041.0 -c Release /p:RuntimeIdentifierOverride=win10-x64 +``` + +Publishing builds and packages the app, copying the signed package to the _bin\\Release\\net6.0-windows10.0.19041.0\\win10-x64\\AppPackages\\\\\_ folder. \ is a folder named after both your project and version. In this folder, there's an _msix_ file, and that's the app package. + +For more information about the `dotnet publish` command, see [dotnet publish](/dotnet/core/tools/dotnet-publish). + +## Installing the app + +To install the app, it must be signed with a certificate that you already trust. If it isn't, Windows won't let you install the app. You'll be presented with a dialog similar to the following, with the Install button disabled: + +:::image type="content" source="media/publish-cli/install-untrusted.png" alt-text="Installing an untrusted app."::: + +Notice that in the previous image, the Publisher was "unknown." + +To trust the certificate of app package, perform the following steps: + +01. Right-click on the _.msix_ file and choose **Properties**. +01. Select the **Digital Signatures** tab. +01. Choose the certificate then press **Details**. + + :::image type="content" source="media/publish-cli/properties-digital-signatures.png" alt-text="Properties pane of an MSIX file with the digital signatures tab selected."::: + +01. Select **View Certificate**. +01. Select **Install Certificate...**. +01. Choose **Local Machine** then select **Next**. + + If you're prompted by User Account Control to **Do you want to allow this app to make changes to your device?**, select **Yes**. + +01. In the **Certificate Import Wizard** window, select **Place all certificates in the following store**. +01. Select **Browse...** and then choose the **Trusted People** store. Select **OK** to close the dialog. + + :::image type="content" source="media/publish-cli/certificate-import.png" alt-text="Certificate import wizard window is shown while selecting the Trusted People store."::: + +01. Select **Next** and then **Finish**. You should see a dialog that says: **The import was successful**. + + :::image type="content" source="media/publish-cli/certificate-import-success.png" alt-text="Certificate import wizard window with a successful import message."::: + +01. Select **OK** on any window opened as part of this process, to close them all. + +Now, try opening the package file again to install the app. You should see a dialog similar to the following, with the Publisher correctly displayed: + +:::image type="content" source="media/publish-cli/install-trusted.png" alt-text="Installing a trusted app."::: + +Select the **Install** button if you would like to install the app. + +## Current limitations + +The following list describes the current limitations with publishing and packaging: + +- The published app doesn't work if you try to run it directly with the executable file out of the publish folder. +- The way to run the app is to first install it through the packaged _MSIX_ file. diff --git a/docs/windows/deployment/publish-visual-studio-folder.md b/docs/windows/deployment/publish-visual-studio-folder.md new file mode 100644 index 000000000..3f6153394 --- /dev/null +++ b/docs/windows/deployment/publish-visual-studio-folder.md @@ -0,0 +1,98 @@ +--- +title: "Publish a .NET MAUI app to a folder for Windows" +description: "Learn how to package and publish a Windows .NET MAUI app to a file share in Visual Studio." +ms.date: 10/06/2022 +--- + +# Publish a .NET MAUI app for Windows with Visual Studio + + + +This article describes how to use Visual Studio to publish your .NET MAUI app for Windows. .NET MAUI apps are packaged into an MSIX package, which is used for installing in Windows or for submission to the Microsoft Store. For more information about the benefits of MSIX, see [What is MSIX?](/windows/msix/overview). + +> [!TIP] +> .NET MAUI currently only allows publishing an MSIX package. You can't yet publish a Windows executable file for distribution. + +## Set the build target + +In Visual Studio, you can only publish to one platform at a time. The target platform is selected with the **Debug Target** dropdown in the Visual Studio toolbar. Set the target to **Windows Machine** or to **Framework** > **net6.0-windows**, as illustrated in the following image: + +:::image type="content" source="media/publish-visual-studio/vs-debugtarget.png" alt-text="Selecting the Windows debug target for a .NET MAUI app in Visual Studio."::: + +## Publish the project + +After the build target is set to Windows, you can publish your project. Perform the following steps: + +01. In the **Solution Explorer** pane, right-click the project and select **Publish**. + + :::image type="content" source="media/publish-visual-studio/vs-right-click-publish.png" alt-text="Right-click on a project file and select publish in Visual Studio"::: + +01. In the **Create App Packages** dialog, select **Sideloading**, and then select **Next**. + + :::image type="content" source="media/publish-visual-studio/vs-1-how-distribute.png" alt-text="The sideloading option selected on Create App Packages dialog box in Visual Studio to publish a .NET MAUI app."::: + + The **Enable automatic updates** checkbox is optional. + + +01. In the **Select Signing Method** dialog, select **Yes, select a certificate**. You can choose a certificate from a variety of sources. This article will create a temporary self-signed certificate for testing. + + :::image type="content" source="media/publish-visual-studio/vs-2-cert-sign.png" alt-text="Package signing method dialog in Visual Studio."::: + + 01. Select **Create**. + + You can create a temporary self-signed certificate for testing. This certificate shouldn't be used to distribute your app package, it should only be used for testing your app's installation process. + + 01. In the **Create a self-signed test certificate** dialog box, enter a company name used to represent the publisher of your app. Next, type in a password for the certificate, and enter the same password into the **Confirm your password** box. + + :::image type="content" source="media/publish-visual-studio/vs-2_1-create-cert.png" alt-text="Create a self-signed test certificate in Visual Studio"::: + + 01. Select **OK** to return to the previous dialog. + + Once you've selected a certificate, you should see the certificate's information displayed in the dialog box. Select the **Next** button to move on to the next dialog. + +01. In the **Select and configure packages** dialog, you can select a version for the app package or leave it at its default of `0.0.0.0`. The **Automatically increment** checkbox determines if the version of the package is increased everytime it's published. + + Select the **Publishing profile** dropdown and select **\** + + :::image type="content" source="media/publish-visual-studio/vs-4-configure.png" alt-text="Showing the New publishing profile item in Visual Studio."::: + + 01. In the **Create a new MSIX Publish Profile** dialog, the default options should be what you want selected. + + :::image type="content" source="media/publish-visual-studio/vs-4_1-publish-profile.png" alt-text="Creating a new publishing profile in Visual Studio."::: + + 01. Select **OK** to return to the previous dialog. + + The publishing profile you created is now selected. + + :::image type="content" source="media/publish-visual-studio/vs-5-configure-done.png" alt-text="Showing the New publishing profile item with a publish profile selected, in Visual Studio."::: + +01. If you chose the option to enable automatic updates for your package, then select the **Next** button. If you didn't select automatic updates, the button reads **Create**, select it, and skip the next step. + +01. The next dialog displayed is the **Configure update settings** dialog. This is where you configure the installer location for your app, and how often the app should check for updates. + + Whenever you publish an updated version of the app, it overwrites the previous version of the app at the **Installer location**. When users run your app, and based on how often your app checks for updates, the app checks this location for an updated version, and if found, installs it. + + :::image type="content" source="media/publish-visual-studio/vs-6-update.png" alt-text="The configure update settings dialog box in Visual Studio."::: + + Once you select an **Installer location**, select **Create**. + +01. After pressing **Create**, the installer is created and the **Finished creating package** dialog is displayed, which summarizes your package. + + :::image type="content" source="media/publish-visual-studio/vs-7-complete.png" alt-text="The finished creating a package dialog in Visual Studio."::: + + There may be two options to close the dialog box. If you have the **Copy and close** button, select it to copy the package to the **Installer location** you selected during the **Configure update settings** step. Otherwise, select **Close** to close the dialog box. + +## Current limitations + +The following list describes the current limitations with publishing and packaging: + +- The published app doesn't work if you try to run it directly with the executable file out of the publish folder. +- The way to run the app is to first install it through the packaged _MSIX_ file.