Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Para um exemplo funcional de ponta a ponta (aplicação WPF + instalador Inno Setup), veja o exemplo da aplicação esparsa.
Um executável padrão de ambiente de trabalho — construído com dotnet build, MSBuild, CMake ou qualquer outra cadeia de ferramentas — não tem identidade de pacote. Sem identidade, não pode utilizar muitas APIs modernas do Windows (notificações do tipo toast, tarefas em segundo plano, destinos de partilha, tarefas de arranque automático, as APIs de dados da aplicação, entre outras).
O empacotamento esparso atribui uma identidade a uma aplicação sem mover os seus binários para um MSIX. Envias um pequeno documento apenas.msix de identidade (apenas um manifesto) e registas-no juntamente com a tua aplicação normalmente instalada usando uma localização externa. A sua .exe fica exatamente onde o seu instalador a colocou. Esta é a contrapartida em produção de winapp create-debug-identity, que se destina apenas à depuração durante o desenvolvimento.
Este guia cobre os três passos da CLI que correspondem aos três primeiros passos do fluxo de trabalho oficial da identidade da Grant para aplicações não embaladas :
| Passo | Comando | Result |
|---|---|---|
| 1. Criar o manifesto de identidade | winapp init --exe <exe> --sparse |
sparse/appxmanifest.xml + sparse/Assets/ |
| 2. Construir e assinar o pacote de identidade | winapp pack <appxmanifest.xml> --cert <pfx> |
<PackageName>.identity.msix |
| 3. Incorporar a identidade na aplicação | winapp embed-identity <exe> |
<msix> elemento no manifesto de fusão do exe |
Os passos 4–5 da documentação (registar / desregistar o pacote) são da responsabilidade do seu instalador — veja Integração do instalador.
Quando usar embalagens esparsas
- Já tens um instalador maduro (Inno Setup, WiX, NSIS, MSI) e não queres mudar para o MSIX para distribuição, mas precisas de APIs do Windows com controlo de identidade.
- A tua aplicação tem de ser instalada num caminho ou com um layout que o MSIX não permite.
- Quer uma mudança mínima e aditiva: mantenha o fluxo de instalação existente e adicione um
.msixpasso de registo.
Se estás a começar do zero e podes distribuir como MSIX, uma aplicação completa (winapp init + winapp pack <folder>) é mais simples.
Pré-requisitos
- Windows 10, versão 2004 (build 19041) ou posterior. Os pacotes esparsos dependem de
uap10:AllowExternalContent, que requer 19041+. -
CLI winapp — instalar via winget (ou atualizar se já estiver instalado):
winget install Microsoft.WinApp --source winget -
Um certificado de assinatura de código confiável na máquina alvo. Para testes locais, gere um certificado de desenvolvimento com
winapp cert generatee confie nele. Os pacotes de produção devem ser assinados com um certificado cujo assunto corresponde ao manifestoPublisher.
Walkthrough
Os exemplos abaixo assumem um executável construído em ./bin/Release/net8.0-windows/MyApp.exe.
Passo 1 — Criar o manifesto de identidade esparso
winapp init --exe ./bin/Release/net8.0-windows/MyApp.exe --sparse
Isto deduz o nome do pacote, o editor, a versão e a descrição a partir do ficheiro exe (através das informações de versão do ficheiro) e pede-lhe que os aceite ou os substitua. Adicionar --use-defaults (ou --no-prompt) para saltar os prompts no CI, e --name / --publisher para sobrescrever valores específicos:
winapp init --exe ./bin/Release/net8.0-windows/MyApp.exe --sparse --use-defaults `
--name "Contoso.MyApp" --publisher "CN=Contoso"
Escreve o seguinte, por predefinição, na pasta dedicada sparse/ do diretório atual (pode ser substituído com --output-dir):
-
appxmanifest.xml— um manifesto disperso com<uap10:AllowExternalContent>true</uap10:AllowExternalContent>(um elemento em<Properties>),ProcessorArchitecture="neutral", uma aplicaçãowin32Appe o nome do exe indicado emExecutable. -
Assets/— ativos visuais provisórios (extraídos do ícone do exe, sempre que possível).
Porquê uma
sparse/pasta e não ao lado do exe? O manifesto eAssets/são entradas em tempo de construção consumidas porwinapp packewinapp embed-identity— nada os lê além do exe em tempo de execução (a identidade em tempo de execução vem do<msix>elemento embutido no exe mais a localização externa do pacote registado, e o manifesto faz referência ao exe pelo nome, pelo que a sua localização é independente de onde o exe está localizado). Escrevê-los numa pasta dedicada, sob controlo de versão, mantém-nos fora de um diretório de saída da compilação (comobin/), que uma limpeza ou recompilação apagaria, e mantém a pasta livre de binários para que as etapas seguintes permaneçam limpas.winapp packewinapp embed-identityprocuram automaticamente emsparse/, por isso raramente é necessário indicar o caminho.
Nota: O fluxo de inicialização simplificado omite deliberadamente toda a instalação de SDKs/pacotes — os pacotes só de identidade não têm dependências de SDK.
Se já existir um appxmanifest.xml no diretório de destino, o init interrompe-se em vez de o sobrescrever (e o seu Assets/). Execute novamente com --force para o regenerar.
Certifica-te de que o Publisher que está no manifesto gerado corresponde ao certificado com que vais assinar. Edita appxmanifest.xml se for necessário, ou passa --publisher ao gerar.
Passo 2 — Construir e assinar o pacote de identidade
Aponte winapp pack para o manifesto esparso (um ficheiro, não uma pasta):
winapp pack ./sparse/appxmanifest.xml --cert ./devcert.pfx
Como o manifesto declara AllowExternalContent, winapp pack constrói uma identidade apenas.msix contendo o manifesto — sem binários, sem ativos. A saída é, por predefinição, <PackageName>.identity.msix no diretório atual; use --output para alterar esse local. A assinatura acontece apenas quando passas --cert (ou --generate-cert).
Passo 3 — Incorpore a identidade na sua aplicação
Incorpore o <msix> elemento para que o Windows ligue o exe em execução ao pacote de identidade:
# EXE mode — modify the built binary in place (uses mt.exe)
winapp embed-identity ./bin/Release/net8.0-windows/MyApp.exe
Ou manter o manifesto side-by-side como um ficheiro versionado e voltar a compilar:
# XML mode — update an external SxS manifest, then rebuild your app
winapp embed-identity ./app.manifest
No modo XML, o <msix> elemento é inserido (ou substituído) no manifesto de destino. Faz referência a esse manifesto no projeto (para .NET, define <ApplicationManifest>app.manifest</ApplicationManifest>) e recompila para que o elemento fique incorporado no ficheiro executável.
Ambos os modos obtêm a identidade a partir de um elemento esparso appxmanifest.xml. Quando omites --manifest, o winapp procura primeiro na pasta sparse/ (onde winapp init --exe --sparse a escreve por predefinição) junto do destino, depois no diretório atual e, por fim, recorre ao diretório junto do destino e ao diretório atual; passa --manifest para indicar outro local.
Nota: O modo EXE reescreve o binário com
mt.exe, o que invalida qualquer assinatura Authenticode existente. Re-assine o exe (por exemplo)winapp sign ./MyApp.exe <cert.pfx>antes de o distribuir.
Passo 4 — Registar-se (para testes locais)
Os logótipos do manifesto são resolvidos a partir da localização externa em tempo de execução, não apenas a partir da identidade .msix. O passo 1 escreveu-os em ./sparse/Assets, por isso copie-os ao lado do seu exe (a localização externa) antes de se registar — caso contrário, o Windows regista um layout sem todos os logótipos que o manifesto refere:
# Copy the generated assets into the external location (beside your exe)
Copy-Item ./sparse/Assets -Destination .\bin\Release\net8.0-windows\Assets -Recurse -Force
Depois regista o pacote de identidade nessa pasta (a localização externa):
Add-AppxPackage -Path .\MyApp.identity.msix `
-ExternalLocation (Resolve-Path .\bin\Release\net8.0-windows)
Inicie a aplicação e confirme que a identidade está presente — por exemplo, Windows.ApplicationModel.Package.Current.Id.FamilyName deve devolver o nome da sua encomenda em vez de o lançar.
Para limpar:
Remove-AppxPackage <full-package-name>
Manuseamento de ativos
O escasso .msix é apenas de identidade. Os ativos visuais referenciados pelo manifesto (Assets\StoreLogo.png, mosaicos, etc.) são obtidos a partir da localização de conteúdo externo em tempo de execução — ou seja, a partir do diretório de instalação da sua aplicação — não do interior do .msix.
Isto significa que tens de implementar a Assets/ pasta juntamente com a tua aplicação (com o mesmo layout que o manifesto espera, relativamente à localização externa).
O Passo 2 empacota diretamente o ficheiro de manifesto (winapp pack ./sparse/appxmanifest.xml), o que cria o .msix apenas de identidade a partir apenas desse manifesto — os ficheiros no mesmo diretório são ignorados, pelo que nunca inclui os seus recursos nem binários. (Se, em vez disso, winapp pack apontar para uma pasta cujo manifesto declara AllowExternalContent, é emitido um aviso sobre quaisquer recursos ou binários encontrados, pois, no caso de um pacote esparso, estes devem estar no local externo, e não no interior de .msix.)
Integração do instalador
O registo e o desregisto são trabalho do instalador. O padrão é o mesmo em todas as ferramentas de instalação:
-
Instalar: copie os binários da sua aplicação, a
Assets/pasta e depois.msixpara o diretório de instalação, depois executeAdd-AppxPackage -Path "<install-dir>\MyApp.identity.msix" -ExternalLocation "<install-dir>". -
Desinstalar: executar
Remove-AppxPackage <full-package-name>antes de apagar ficheiros.
Segurança: o diretório de instalação é resolvido no momento da instalação e pode conter caracteres (por exemplo, uma única aspas) que se separam de uma string literal do PowerShell. Escape ou valide sempre o caminho antes de o interpolar numa
-Commandstring — os excertos do WiX e NSIS abaixo assumem um caminho de instalação confiável, enquanto o exemplo do Inno Setup demonstra escape seguro. Prefira passar caminhos como argumentos para um script-Fileem vez de interpolação em linha-Command.
Configuração Inno
Crie os argumentos do PowerShell numa função [Code] para que o caminho da instalação em tempo de execução seja escapado no literal do PowerShell entre aspas simples (um diretório de instalação que contenha um ' não deve conseguir injetar um script):
[Files]
Source: "dist\*"; DestDir: "{app}"; Flags: recursesubdirs
Source: "MyApp.identity.msix"; DestDir: "{app}"
[Run]
Filename: "powershell.exe"; Parameters: "{code:RegisterParams}"; Flags: runhidden
[UninstallRun]
Filename: "powershell.exe"; \
Parameters: "-NoProfile -ExecutionPolicy Bypass -Command ""Get-AppxPackage -Name 'MyApp' | Remove-AppxPackage"""; \
Flags: runhidden
[Code]
function EscapePSLiteral(const Value: string): string;
var S: string;
begin
S := Value; StringChange(S, '''', ''''''); Result := S;
end;
function RegisterParams(Param: string): string;
var AppDir: string;
begin
AppDir := ExpandConstant('{app}');
{ -ErrorAction Stop + try/catch make a registration failure terminating, so powershell.exe
exits nonzero and the AfterInstall callback (see the full sample) can abort with rollback. }
Result := '-NoProfile -ExecutionPolicy Bypass -Command "try { Add-AppxPackage -Path ''' +
EscapePSLiteral(AppDir + '\MyApp.identity.msix') +
''' -ExternalLocation ''' + EscapePSLiteral(AppDir) + ''' -ErrorAction Stop } catch { Write-Error $_; exit 1 }"';
end;
Consulte o exemplo sparse-app para ver um setup.iss completo e funcional.
Os exemplos do WiX e do NSIS abaixo invocam uma pequena -File através de register-sparse.ps1 para que o caminho de instalação seja passado como parâmetro (o PowerShell trata-o como dados) em vez de ser interpolado numa -Command cadeia de caracteres. Isto evita a injeção de scripts através de um diretório de instalação criado (por exemplo, um nome de pasta contendo uma citação ou $(...)):
# register-sparse.ps1 — ship this alongside your installer
param(
[Parameter(Mandatory)] [string] $MsixPath,
[Parameter(Mandatory)] [string] $ExternalLocation,
[Parameter(Mandatory)] [string] $PackageName
)
$ErrorActionPreference = 'Stop'
try {
# Add-AppxPackage emits NON-terminating errors by default, so a failure would otherwise leave
# the process exit code at 0 and let the installer complete without identity. Try the add
# directly first: a fresh install or a version-bumped upgrade registers/updates in place
# without touching any existing registration. -ErrorAction Stop + the outer trap make a real
# failure terminating so the installer (WiX Return="check" / NSIS) sees it.
try {
Add-AppxPackage -Path $MsixPath -ExternalLocation $ExternalLocation -ErrorAction Stop
} catch {
# Only ONE failure is safe to resolve by unregister+retry: the exact same version is already
# registered (HRESULT 0x80073CFB, ERROR_PACKAGE_ALREADY_EXISTS — "already installed,
# reinstallation blocked"), which Add-AppxPackage rejects. Re-throw everything else
# (untrusted/corrupt .msix, unsupported OS, ...) so a bad new package can NEVER unregister a
# working prior registration and strip the installed app of the identity it already had.
if ($_.Exception.HResult -ne 0x80073CFB) { throw }
Get-AppxPackage -Name $PackageName | Remove-AppxPackage -ErrorAction SilentlyContinue
Add-AppxPackage -Path $MsixPath -ExternalLocation $ExternalLocation -ErrorAction Stop
}
} catch {
Write-Error $_
exit 1
}
WiX (v3)
Registar por utilizador (Impersonate="yes"), porque Add-AppxPackage regista o pacote na conta que o executa. Uma ação diferida com Impersonate="no" executa-se como LocalSystem, que não concede identidade ao utilizador instalador (e é frequentemente rejeitada). Para um MSI por máquina, execute o registo como se fizesse passar para que se aplique ao utilizador que invocou.
Uma ação personalizada diferida não consegue ler INSTALLFOLDER diretamente (as ações diferidas são executadas num contexto sem acesso às propriedades), e simplesmente declarar a ação não faz com que ela seja executada. Assim, encaminhe os caminhos através de CustomActionData — uma ação imediata do tipo 51 cujo Property nome é igual ao da ação diferida Id — e agende ambos depois de InstallFiles:
<!-- Immediate: stash the command line (with the resolved paths) into the deferred action's
CustomActionData. Windows Installer copies the value of the property named the same as a
deferred action into that action's CustomActionData. -->
<CustomAction Id="SetRegisterSparseCmd" Property="RegisterSparse" Execute="immediate"
Value="powershell.exe -NoProfile -ExecutionPolicy Bypass -File "[INSTALLFOLDER]register-sparse.ps1" -MsixPath "[INSTALLFOLDER]MyApp.identity.msix" -ExternalLocation "[INSTALLFOLDER]" -PackageName "MyPackageIdentityName"" />
<!-- Deferred + impersonated: CAQuietExec reads its command line from CustomActionData when run
deferred, so it registers the package for the invoking user. Return="check" fails the
install if registration fails. -->
<CustomAction Id="RegisterSparse" BinaryKey="WixCA" DllEntry="CAQuietExec"
Execute="deferred" Impersonate="yes" Return="check" />
<InstallExecuteSequence>
<Custom Action="SetRegisterSparseCmd" After="InstallFiles">NOT Installed</Custom>
<Custom Action="RegisterSparse" After="SetRegisterSparseCmd">NOT Installed</Custom>
</InstallExecuteSequence>
CAQuietExec é fornecido com a extensão util do WiX (WixUtilExtension); faça referência à mesma para que o binário WixCA esteja disponível.
Uma única ação personificada regista a identidade apenas para o utilizador que executa o instalador. Para aprovisionar todos os utilizadores de uma instalação por máquina, faça antes o registo no primeiro arranque (por utilizador) ou utilize um mecanismo de aprovisionamento como
Add-AppxProvisionedPackage.
NSIS
Section
# Capture the PowerShell exit code and abort if registration failed. register-sparse.ps1 exits
# nonzero on failure (it sets $ErrorActionPreference='Stop' and traps), so without this check the
# installer would complete even though the app has no identity.
ExecWait 'powershell.exe -NoProfile -ExecutionPolicy Bypass -File "$INSTDIR\register-sparse.ps1" -MsixPath "$INSTDIR\MyApp.identity.msix" -ExternalLocation "$INSTDIR" -PackageName "MyPackageIdentityName"' $0
IntCmp $0 0 +2
Abort "Registering the sparse identity package failed (exit code $0). The app requires package identity."
SectionEnd
Solução de problemas
Package.Current gera o erro / "sem identidade do pacote" em tempo de execução
- O pacote de identidade não está registado, ou o manifesto de fusão do exe não tem o
<msix>elemento. Executewinapp embed-identitynovamente (e reconstrua se usar modo XML), depois volte a registar comAdd-AppxPackage -ExternalLocation. - O
<msix packageName>/applicationId/publisherno exe deve corresponder exatamente à identidade da encomenda registada.
Recursos/logótipos não aparecem
- Certifique-se de que a pasta
Assets/seja disponibilizada no local externo com os mesmos caminhos relativos que o manifesto especifica. Os ativos são resolvidos a partir da localização externa, não do.msix.
Add-AppxPackage falha devido a um erro de assinatura / confiança
- O
.msixdeve ser assinado por um certificado que seja confiável na máquina e cujo assunto corresponda ao manifestoPublisher. Para testes locais, gere e confia num certificado de desenvolvimento comwinapp cert generate, e certifica-te de que o manifestoPublishercorresponde a ele.
MakeAppx: "A aplicação com valor RuntimeBehavior 'win32App' não deve declarar o EntryPoint"
- Uma aplicação dispersa
win32Appnão deve declararEntryPoint. Os manifestos gerados porwinapp init --sparsejá estão corretos; remova qualquerEntryPointatributo se tiver editado manualmente o manifesto.
"A entrada é um ficheiro mas não um manifesto esparso"
-
winapp pack <file>só aceita um manifesto que declara<uap10:AllowExternalContent>true</uap10:AllowExternalContent>. Gera um comwinapp init --exe <exe> --sparse, ou passe uma pasta de entrada para construir um MSIX completo.
Consulte também
Windows developer