Condividi tramite


Attribuire manualmente un'identità al pacchetto tramite il packaging con posizione esterna

Perché farlo? Concedere all'app un'identità del pacchetto (detta anche pacchetto sparse o packaging con posizione esterna) sblocca le funzionalità della piattaforma Windows altrimenti non disponibili per le app non in pacchetto: notifiche di tipo avviso popup e push, attività in background, estensioni dell'app, destinazioni di condivisione, associazioni di file, attività di avvio, richieste di consenso sulla privacy e Windows API di AI Foundry: tutte senza passare alla creazione completa di pacchetti MSIX o alla modifica del programma di installazione esistente.

Per altre informazioni sulle motivazioni alla base dell'aggiunta dell'identità del pacchetto, nonché sulle differenze tra la creazione di pacchetti di identità in Visual Studio e la compilazione manuale, vedere Overview.

Questo argomento descrive come compilare e registrare manualmente un pacchetto di identità. Per informazioni sulla creazione di un pacchetto di identità in Visual Studio, vedere Conferire l'identità del pacchetto tramite il confezionamento con una posizione esterna in Visual Studio.

Questi sono i passaggi descritti in dettaglio in questo argomento per compilare e registrare manualmente un pacchetto di identità:

  1. Creare un manifesto del pacchetto per il pacchetto identity
  2. Compilare e firmare il pacchetto di identità
  3. Aggiungere metadati di identità ai manifesti dell'applicazione desktop
  4. Registrare il pacchetto di identità nel programma di installazione
  5. Passaggi facoltativi

Creare un manifesto del pacchetto per il pacchetto identity

Il primo passaggio per creare un pacchetto identity consiste nel creare un manifesto del pacchetto basato sul modello seguente. Si tratta di un manifesto MSIX, ma viene usato solo per l'identità e non modifica il comportamento di runtime dell'app.

<?xml version="1.0" encoding="utf-8"?>
<Package IgnorableNamespaces="uap uap10"
  xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
  xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
  xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10"
  xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities">
  <Identity Name="ContosoPhotoStore" Publisher="CN=Contoso" Version="1.0.0.0" ProcessorArchitecture="neutral" />
  <Properties>
    <DisplayName>Contoso PhotoStore</DisplayName>
    <PublisherDisplayName>Contoso</PublisherDisplayName>
    <Logo>Assets\storelogo.png</Logo>
    <uap10:AllowExternalContent>true</uap10:AllowExternalContent>
  </Properties>
  <Resources>
    <Resource Language="en-us" />
  </Resources>
  <Dependencies>
    <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.26100.0" />
  </Dependencies>
  <Capabilities>
    <rescap:Capability Name="runFullTrust" />
    <rescap:Capability Name="unvirtualizedResources"/>
  </Capabilities>
  <Applications>
    <Application Id="ContosoPhotoStore" Executable="ContosoPhotoStore.exe" uap10:TrustLevel="mediumIL" uap10:RuntimeBehavior="win32App"> 
      <uap:VisualElements AppListEntry="none" DisplayName="Contoso PhotoStore" Description="Contoso PhotoStore App" BackgroundColor="transparent" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" />
    </Application>
  </Applications>
</Package>

Si notino i dettagli importanti seguenti su questo manifesto:

  • Compilare gli attributi dell'elemento Identity con i dettagli dell'applicazione
    • Name è il nome desiderato del pacchetto di identità
    • Publisher deve corrispondere al Subject del certificato usato per firmare l'applicazione
    • Version è la versione desiderata del pacchetto di identità. Una pratica comune consiste nell'allineare la versione del pacchetto di identità alla versione dell'applicazione. Non sarà possibile registrare una versione di un pacchetto di identità in un sistema se tale versione del pacchetto è già registrata. È prima necessario annullare la registrazione del pacchetto esistente per reinstallare un pacchetto con la stessa versione.
    • ProcessorArchitecture deve essere neutral come illustrato in modo che il pacchetto di identità funzioni in tutte le architetture (x86, x64 e ARM64)
  • Riempire gli elementi DisplayName e PublisherDisplayName con i dettagli della tua applicazione
    • A meno che non si aggiungono funzionalità aggiuntive al manifesto oltre alla semplice identità, questi valori non vengono visualizzati ovunque
  • Aggiornare l'elemento Logo a un percorso relativo all'interno della directory di installazione dell'applicazione in modo che si risolva in un'immagine in formato .png, .jpgo .jpeg
  • Assicurarsi che l'elemento AllowExternalContent sia impostato su true come illustrato, che consente di riutilizzare il programma di installazione esistente
  • Impostare TargetDeviceFamilyMinVersion e MaxVersionTested come indicato di seguito:
    • Scegliere un MinVersion valore in base al sistema operativo minimo supportato:
      • 10.0.19041.0 : consigliato per la massima copertura tra Windows 10 e Windows 11
      • 10.0.26100.0: usare questa opzione solo se l'app è destinata esclusivamente a Windows 11, versione 24H2 o successiva
    • Imposta MaxVersionTested su 10.0.26100.0 come illustrato
    • Nota: la funzionalità AllowExternalContent usata qui è stata introdotta in Windows build 10.0.19041.0. Se l'applicazione viene eseguita più in basso, è necessario eseguire un controllo della versione del sistema operativo nel programma di installazione e non registrare il pacchetto di identità nelle versioni del sistema operativo precedenti alla 10.0.19041.0. Vedere Registrare il pacchetto di identità nel programma di installazione.
  • Verificare che le funzionalità runFullTrust e unvirtualizedResources siano dichiarate come illustrato per la compatibilità Win32
  • Aggiungere un Application elemento come illustrato per ogni eseguibile associato all'applicazione
    • Assicurarsi che TrustLevel sia mediumIL e che RuntimeBehavior sia win32App come mostrato per la compatibilità Win32
  • L'elemento VisualElements figlio è obbligatorio, ma l'attributo AppListEntry="none" garantisce che il pacchetto di identità non venga visualizzato tra le app installate
    • Aggiornare gli attributi DisplayName e Description con i dettagli pertinenti e lasciare gli altri attributi come illustrato (non è necessario risolvere i percorsi di immagine a cui si fa riferimento)
    • Vedere Localizzazione e asset visivi per gli scenari in cui potrebbero essere necessarie la localizzazione e le immagini qui.

Il pacchetto di identità creato da questo manifesto verrà connesso alla directory di installazione dell'applicazione quando si registra il pacchetto in un passaggio successivo.

Compilare e firmare il pacchetto di identità

Dopo aver creato il manifesto del pacchetto di identità, costruire il pacchetto di identità usando lo strumento MakeAppx.exe nel Windows SDK.

MakeAppx.exe pack /o /d <path to directory that contains manifest> /nv /p <output path>\MyPackage.msix

Nota: il /nv flag è necessario per ignorare la convalida dei percorsi di file a cui si fa riferimento nel manifesto.

Per essere installato nei computer degli utenti finali, il pacchetto di identità deve essere firmato con un certificato attendibile nel computer di destinazione. È possibile creare un nuovo certificato autofirmato a scopo di sviluppo e firmare il pacchetto di identità usando SignTool disponibile nell'SDK di Windows, ma per registrare il pacchetto nei computer degli utenti finali sarà necessario un certificato di produzione di un reparto IT o di un servizio come Firma attendibile di Azure.

SignTool.exe sign /fd SHA256 /a /f <path to certificate>\MyCertificate.pfx /p <certificate password> <path to package with external location>\MyPackage.msix

Importante

Quando si usa un certificato autofirmato per lo sviluppo locale, è necessario aggiungerne il certificato pubblico all'archivio certificati Persone attendibili prima Add-AppxPackage di accettarlo. Senza questo passaggio, la registrazione non riesce con CERT_E_UNTRUSTEDROOT (0x800B0109).

Mantenere il .pfx file privato: contiene la chiave privata e deve essere usata solo per la firma. Per il passaggio di attendibilità, esportare solo un .cer certificato pubblico e quindi importarlo:

$cert = Get-PfxCertificate -FilePath "<path>\MyCertificate.pfx"
Export-Certificate -Cert $cert -FilePath "<path>\MyCertificate.cer"
Import-Certificate -FilePath "<path>\MyCertificate.cer" `
    -CertStoreLocation Cert:\CurrentUser\TrustedPeople

Per le installazioni a livello di computer, usare Cert:\LocalMachine\TrustedPeople invece (richiede privilegi elevati).

I certificati di produzione rilasciati da una CA attendibile non richiedono questo passaggio.

Nota: per informazioni su come compilare e firmare il pacchetto di identità all'interno di una pipeline CI/CD con certificati di produzione, vedere la panoramica della pipeline MSIX e CI/CD per esempi.

Aggiungere metadati di identità ai manifesti dell'applicazione desktop

È possibile connettere il pacchetto di identità con i file eseguibili dell'applicazione includendo manifesti dell'applicazione (ad esempio manifesti side-by-side o fusion) con metadati corrispondenti ai metadati del manifesto del pacchetto di identità.

In Visual Studio è possibile aggiungere un manifesto application a un project eseguibile aprendo il menu di scelta rapida Project e selezionando Add>New Item>Application Manifest File.

Di seguito è riportato un frammento di manifesto dell'applicazione di esempio che illustra l'elemento msix necessario per connettere i file binari con i metadati del pacchetto identity.

<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <assemblyIdentity version="0.0.0.0" name="ContosoPhotoStore"/>
  <msix xmlns="urn:schemas-microsoft-com:msix.v1"
          publisher="CN=Contoso"
          packageName="ContosoPhotoStore"
          applicationId="ContosoPhotoStore"
        />
</assembly>

Gli attributi dell'elemento msix devono corrispondere a questi valori dal manifesto del pacchetto di identità:

  • Gli attributi packageName e publisher devono corrispondere rispettivamente agli attributi Name e Publisher nell'elemento Identity nel manifesto del pacchetto di identità
  • L'attributo applicationId deve corrispondere all'attributo Id dell'elemento corrispondente Application nel manifesto del pacchetto di identità

Registrare il pacchetto di identità nel programma di installazione

L'ultimo passaggio per associare l'identità all'applicazione consiste nel registrare il pacchetto di identità nel programma di installazione e associarlo alla directory di installazione dell'applicazione.

PowerShell

L'esecuzione di powershell.exe con i parametri corretti è il modo più semplice per registrare il pacchetto. Le istruzioni sono diverse per le installazioni per utente o su tutta la macchina.

Per-User (PowerShell)

Per registrare il pacchetto di identità durante un'installazione per utente:

powershell.exe -NoLogo -NoProfile -NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -Command "Add-AppxPackage -Path <PackagePath> -ExternalLocation <ExternalLocation>"
  • Impostare <PackagePath> sul percorso assoluto del pacchetto di identità firmato prodotto nel passaggio precedente (con il nome del file).
  • Impostare <ExternalLocation> sul percorso assoluto della directory di installazione dell'applicazione (senza nomi eseguibili).

Per deregistrare il pacchetto di identità durante una disinstallazione per singolo utente:

powershell.exe -NoLogo -NoProfile -NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -Command "Get-AppxPackage <PackageName> | Remove-AppxPackage"
  • Impostare <PackageName> sul nome del pacchetto definito nel manifesto del pacchetto di identità (l'attributo Name dell'elemento Identity )

Per-Machine (PowerShell)

Per registrare il pacchetto di identità durante un'installazione a livello di computer:

powershell.exe -NoLogo -NoProfile -NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -Command "Add-AppxPackage -Stage <PackagePath> -ExternalLocation <ExternalLocation>; Add-AppxProvisionedPackage -Online -PackagePath <PackagePath>"
  • Impostare <PackagePath> sul percorso assoluto del pacchetto di identità firmato prodotto nel passaggio precedente (con il nome del file).
  • Impostare <ExternalLocation> sul percorso assoluto della directory di installazione dell'applicazione (senza nomi eseguibili).

Per annullare la registrazione del pacchetto di identità durante una disinstallazione a livello di sistema:

powershell.exe -NoLogo -NoProfile -NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -Command "$packages = Get-AppxPackage -AllUsers -Name <PackageName>; $provisioned = Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -eq '<PackageName>' }; foreach ($p in $provisioned) { Remove-AppxProvisionedPackage -PackageName $p.PackageName -Online }; foreach ($package in $packages) { Remove-AppxPackage -Package $package.PackageFullName -AllUsers }"
  • Impostare <PackageName> sul nome del pacchetto definito nel manifesto del pacchetto di identità (l'attributo Name dell'elemento Identity )

API di PackageManager

Se si preferisce chiamare le API del sistema operativo per registrare e annullare la registrazione del pacchetto di identità, l'API PackageManager fornisce funzionalità equivalenti a PowerShell. Le istruzioni sono diverse per le installazioni per utente o su tutta la macchina.

Di seguito sono riportati frammenti di codice che illustrano l'API. Per il codice pronto per la produzione in C# e C++, vedere App di esempio.

Per Utente (GestorePacchetti)

L'elenco di codice seguente illustra la registrazione del pacchetto identity usando il metodo AddPackageByUriAsync e annullando la registrazione del pacchetto identity usando il metodo RemovePackageAsync .

using Windows.Management.Deployment;

...

// Register the identity package during install

var externalUri = new Uri(externalLocation);
var packageUri = new Uri(packagePath);

var packageManager = new PackageManager();

var options = new AddPackageOptions();
options.ExternalLocationUri = externalUri;

var result = await packageManager.AddPackageByUriAsync(packageUri, options);
if (result.ExtendedErrorCode != 0)
{
    throw new Exception($"Package registration failed: {result.ErrorText} (0x{result.ExtendedErrorCode:X8})");
}

...

// Unregister the identity package during uninstall

var packageManager = new PackageManager();
var packages = packageManager.FindPackagesForUserWithPackageTypes("", "<IdentityPackageFamilyName>", PackageTypes.Main);
foreach (var package in packages)
{
  await packageManager.RemovePackageAsync(package.Id.FullName);
}

Si notino i dettagli importanti seguenti su questo codice:

  • Impostare externalLocation sul percorso assoluto della directory di installazione dell'applicazione (senza nomi eseguibili). new Uri(somePath) produce un file:/// URI come richiesto dall'API.
  • Impostare packagePath al percorso assoluto del pacchetto di identità firmato prodotto nel passaggio precedente (incluso il nome del file)
  • Il <IdentityPackageFamilyName> può essere trovato eseguendo il comando PowerShell Get-AppxPackage <IdentityPackageName> su un sistema in cui è registrato il pacchetto di identità. La PackageFamilyName proprietà contiene il valore da usare qui.
  • Controllare result.ExtendedErrorCode dopo la registrazione per visualizzare i dettagli degli errori attuabili. Vedere Risoluzione dei problemi per i codici di errore comuni.

Per-Machine (GestorePacchetti)

L'elenco di codice seguente illustra la registrazione del pacchetto di identità usando i metodi StagePackageByUriAsync e ProvisionPackageForAllUsersAsync e annullando la registrazione del pacchetto identity usando i metodi DeprovisionPackageForAllUsersAsync e RemovePackageAsync .

// Register the identity package during install

var externalUri = new Uri(externalLocation);
var packageUri = new Uri(packagePath);

var packageManager = new PackageManager();

var options = new StagePackageOptions();
options.ExternalLocationUri = externalUri;

await packageManager.StagePackageByUriAsync(packageUri, options);
var packageFamilyName = "<IdentityPackageFamilyName>";
await packageManager.ProvisionPackageForAllUsersAsync(packageFamilyName);

...

// Unregister the identity package during uninstall

var packageManager = new PackageManager();

var packages = packageManager.FindPackagesForUserWithPackageTypes("", "<IdentityPackageFamilyName>", PackageTypes.Main);
foreach (var package in packages)
{
  await packageManager.DeprovisionPackageForAllUsersAsync(package.Id.FullName);
  await packageManager.RemovePackageAsync(package.Id.FullName, RemovalOptions.RemoveForAllUsers);
}

Si notino i dettagli importanti seguenti su questo codice:

  • Impostare externalLocation sul percorso assoluto della directory di installazione dell'applicazione (senza nomi eseguibili)
  • Impostare packagePath sul percorso assoluto del pacchetto di identità firmato prodotto nel passaggio precedente (con il nome del file)
  • Il <IdentityPackageFamilyName> può essere trovato eseguendo il comando PowerShell Get-AppxPackage <IdentityPackageName> su un sistema in cui è registrato il pacchetto di identità. La PackageFamilyName proprietà contiene il valore da usare qui.

Risoluzione dei problemi

La tabella seguente elenca gli errori più comuni durante la registrazione di un pacchetto di identità e come risolverli.

Codice di errore Sintomo Motivo Correzione
0x800B0109 / CERT_E_UNTRUSTEDROOT Add-AppxPackage o AddPackageByUriAsync fallisce immediatamente Il certificato autofirmato non si trova nell'archivio Persone attendibili Seguire il passaggio di attendibilità del certificato sopra indicato per importare la chiave pubblica .cer in Cert:\CurrentUser\TrustedPeople
0x80073CF9 La registrazione fallisce con l'errore "versione già registrata" La stessa versione del pacchetto è già registrata in questo computer Annullare la registrazione del pacchetto esistente prima (Remove-AppxPackage o RemovePackageAsync), quindi ripetere la registrazione
0x80073D54 La registrazione ha esito positivo, ma l'identità è mancante in fase di esecuzione publisher, packageName, o applicationId nel manifesto side-by-side dell'app (elemento msix) non corrispondono al manifesto del pacchetto di identità Assicurarsi che Publisher/Name/Application Id siano identici in entrambi i manifesti. Vedere Aggiungi metadati di identità
Identità assente in fase di esecuzione (nessun errore) Package.Current è null o GetPackage() non restituisce nulla Il ExternalLocation percorso passato alla registrazione non corrisponde alla directory in cui viene effettivamente eseguita l'app Verificare che il percorso assoluto passato come ExternalLocation sia esattamente la directory di installazione dell'app.
0x80073CF6 La registrazione fallisce con "manifest non valido" Il formato XML del manifesto non è valido o manca un attributo obbligatorio Convalidare il manifesto con MakeAppx.exe pack , segnala gli errori dello schema. Assicurarsi che uap10:AllowExternalContent sia true e che la funzionalità runFullTrust sia dichiarata.

Suggerimento

Per una diagnostica più completa, controllare Windows Visualizzatore eventi in Applications and Services Logs > Microsoft > Windows > AppxDeployment-Server. Registra l'errore di distribuzione completo con il contesto che non viene sempre visualizzato nel risultato dell'API o nell'output di PowerShell.

App di esempio

Vedere gli esempi PackageWithExternalLocation per app C# e C++ completamente funzionali che illustrano come registrare e annullare la registrazione di un pacchetto di identità.

Passaggi opzionali

Localizzazione e asset visivi

Alcune funzionalità che comprendono l'identità del pacchetto possono comportare la visualizzazione di stringhe e immagini dal manifesto del pacchetto di identità nel sistema operativo Windows. Per esempio:

  • Un'applicazione che usa le API della fotocamera, del microfono o della posizione avrà un interruttore di controllo dedicato nelle Impostazioni privacy di Windows insieme a una richiesta di consenso mediata che gli utenti possono usare per concedere o negare l'accesso a tali risorse sensibili.
  • Un'applicazione che registra una destinazione di condivisione verrà visualizzata nella finestra di dialogo di condivisione.

Per localizzare le stringhe nel manifesto del pacchetto di identità, vedere Localizzare il manifesto.

Quando si forniscono percorsi alle immagini negli attributi VisualElements nel manifesto del pacchetto di identità, i percorsi specificati devono essere percorsi relativi rispetto alla directory di installazione dell'applicazione e devono risolvere in un'immagine .png, .jpgo .jpeg. I nomi degli attributi indicano le dimensioni previste delle immagini (150x150 e 40x40).