패키지 ID 는 공간과 시간에 걸쳐 고유한 식별자입니다. DNA가 당신을 고유하게 식별하는 것처럼 패키지 ID는 패키지를 고유하게 식별합니다.
패키지에는 연결된 비트 집합(파일 등)이 있습니다. 두 패키지에 동일한 ID가 없으며 패키지와 연결된 비트를 변경하려면 다른 ID가 필요합니다.
패키지 ID란?
패키지 ID는 패키지를 고유하게 식별하는 논리적 구문입니다. ID에는 다음과 같은 5개 부분이 있습니다.
- 이름: 앱 개발자가 선택한 이름입니다. Microsoft Store는 스토어 내의 모든 앱 개발자에게 모든 앱 이름의 고유성을 적용하지만 이름이 일반 에코시스템에서 고유하지는 않습니다.
- 버전: 패키지의 버전 번호입니다. 앱 개발자는 임의의 버전 번호를 선택할 수 있지만 업데이트에 따라 버전 번호가 증가하도록 해야 합니다.
- 건축학: 패키지의 대상이 되는 프로세서 아키텍처입니다. 동일한 앱은 각 빌드가 별도의 패키지에 포함되어 있는 상태로, 서로 다른 프로세서 아키텍처를 목표로 하여 빌드될 수 있습니다.
-
ResourceId: 앱 개발자가 리소스 패키지를 고유하게 식별하기 위해 선택한 문자열(예: 다른 언어 또는 다른 표시 크기 조정)입니다. 리소스 패키지는 일반적으로 아키텍처 중립적입니다. 번들의 경우 ResourceId은 항상
~
이다. - 게시자: 서명 인증서로 식별된, 앱 개발자의 주체 이름. 신뢰할 수 있는 인증 기관에서 고유한 실제 이름과 ID를 사용하여 인증서의 주체 이름 필드를 채우기 때문에 이는 이론적으로 각 앱 개발자에게 고유합니다.
이 구조는 때때로 5부 튜플라고도 합니다.
비고
서명되지 않은 패키지 (1)에는 여전히 Publisher필요합니다. (2) Publisher 서명되지 않은 표식(OID.2.25.31172936891398431)을 포함해야 합니다.76544077305949569997722=1), (3) 서명되지 않은 표식 Publisher 문자열의 마지막 필드여야 하며(4) 서명되지 않은 패키지에 대한 인증서 또는 서명이 없습니다.
패키지 ID 필드 제한
분야 | 데이터 형식 | 제한 | 코멘트 |
---|---|---|---|
이름 | 패키지 문자열 | 최소: 3 최대: 50 |
유효성 검사 API당 허용되는 값( 패키지 문자열 참조) |
버전 | DotQuad | 최소: 0.0.0.0 최대: 65535.65535.65535.65535 |
문자열 형식은 base-10 점선 표기법인 "Major.Minor.Build.Revision"을 사용합니다. |
건축학 | 열거 | 최소: 해당없음 Max: 해당 없음 |
허용되는 값은 "neutral", "x86", "x64", "arm", "arm64", "x86a64"입니다. |
리소스 ID | 패키지 문자열 | 최소: 0 최대: 30 |
유효성 검사 API당 허용되는 값( 패키지 문자열 참조) |
게시자 | 문자열 | 최소: 1 최대: 8192 |
X.509당 허용되는 값 |
퍼블리셔아이디 | 문자열 | 최소: 13 최대: 13 |
Base32 인코딩, 크록포드 방식, 즉 [a-hjkmnp-tv-z0-9] |
'패키지 문자열'이란?
패키지 문자열은 다음 문자를 허용하는 문자열입니다.
- 허용되는 입력 문자(ASCII 하위 집합)
- 대문자(U+0041에서 U+005A까지)
- 소문자(U+0061에서 U+007A까지)
- 숫자(U+0030에서 U+0039까지)
- 점(U+002E)
- 대시(U+002D)
다음 값은 패키지 문자열로 사용할 수 없습니다.
조건 | 금지된 값 |
---|---|
같을 수 없음 | ".", "..", "con", "prn", "aux", "nul", "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9" |
으로 시작할 수 없습니다. | "con.", "prn.", "aux.", "nul.", "com1.", "com2.", "com3.", "com4.", "com5.", "com6.", "com7.", "com8.", "com9.", "lpt1.", "lpt2.", "lpt3.", "lpt4.", "lpt5.", "lpt6.", "lpt7.", "lpt8.", "lpt9.", "xn--" |
~로 끝낼 수 없음 | "." |
포함할 수 없음 | .xn-- |
패키지 문자열은 대소문자를 구분하지 않는 서수 문자열 비교 API(예: _wcsicmp)를 사용하여 비교해야 합니다.
패키지 ID name
및 resourceid
필드는 패키지 문자열입니다.
PackageId 객체
PackageId 5부로 구성된 튜플을 개별 필드(Name
, Version
, Architecture
, ResourceId
, Publisher
)로 포함하는 개체입니다.
패키지 전체 이름
패키지 전체 이름은 패키지 ID의 5개 부분(이름, 버전, 아키텍처, resourceid, 게시자)에서 파생된 불투명 문자열입니다.
<Name>_<Version>_<Architecture>_<ResourceId>_<PublisherId>
예를 들어 Windows 사진 앱의 패키지 전체 이름은 "Microsoft.Windows.Photos_2020.20090.1002.0_x64__8wekyb3d8bbwe"입니다. 여기서 "Microsoft.Windows.Photos"는 이름이고, "2020.20090.1002.0"은 버전 번호이고, "x64"는 대상 프로세서 아키텍처이고, 리소스 ID는 비어 있으며(마지막 두 밑줄 사이에 콘텐츠가 없음), "8wekyb3d8bbwe"는 Microsoft의 게시자 ID입니다.
패키지 전체 이름MSIX 패키지 또는 번들을 고유하게 식별합니다. 콘텐츠가 다르지만 패키지 전체 이름이 동일한 두 개의 패키지 또는 번들을 갖는 것은 오류입니다.
비고
MSIX는 이전 용어 APPX의 새 이름입니다. 자세한 내용은 MSIX란?
패키지 패밀리 이름
패키지 패밀리 이름은 패키지 ID의 두 부분(이름 및 게시자)에서 파생된 불투명 문자열입니다.
<Name>_<PublisherId>
예를 들어 Windows 사진 앱의 패키지 패밀리 이름은 "Microsoft.Windows.Photos_8wekyb3d8bbwe"입니다. 여기서 "Microsoft.Windows.Photos"는 이름이고 "8wekyb3d8bbwe"는 Microsoft의 게시자 ID입니다.
패키지 패밀리 이름은 종종 '버전 없는 패키지 전체 이름'이라고 합니다.
비고
패키지 패밀리 이름에는 아키텍처 및 리소스 ID도 부족하기 때문에 이는 엄격히 사실이 아닙니다.
비고
데이터 및 보안은 일반적으로 패키지 패밀리로 범위가 지정됩니다. 예를 들어, 메모장 버전 1.0.0.0 패키지에서 설치된 메모장 앱을 Wordwrap을 사용하도록 구성한 경우 사용자 경험이 좋지 않을 것입니다. 그런 다음 메모장을 1.0.0.1로 업데이트하고 구성 데이터가 최신 버전의 패키지로 전달되지 않았습니다.
게시자 ID
패키지 패밀리 이름은 형식이 있는 문자열입니다.
<name>_<publisherid>
여기서 게시자 ID에는 매우 구체적인 속성이 있습니다.
- 출판사에서 유래됨
- MinLength = MaxLength = 13자 [고정 크기]
- 허용되는 문자(regex로) = a-hj-km-np-tv-z0-9
- Base-32, Crockford Variant, 즉 영숫자(A-Z0-9)는 I(눈), L(ell), O(오) 또는 U(사용자)를 제외하고
- 대소문자를 구분하지 않는 서수 비교 --- ABCDEFABCDEFG == abcdefabcdefg
따라서 당신은 %를 절대 볼 수 없을 것입니다: \ / " ? 또는 게시자 ID에 포함된 다른 문자
자세한 내용은 PackageFamilyNameFromId 및 PackageNameAndPublisherIdFromFamilyName 참조하세요.
게시자 ID를 PublisherId라고도 합니다.
게시자 ID가 존재하는 이유는 무엇인가요?
게시자가 인증서의 X.509 이름/서명자와 일치해야 하므로 게시자 ID가 존재합니다.
- 그것은 매우 클 수 있습니다 (길이 <= 8192 문자)
- 어색하거나 제한된 문자(백슬래시 등)를 포함할 수 있습니다.
이러한 문제는 일부 X.509 문자열을 파일 시스템, 레지스트리, URL 및 기타 컨텍스트에서 사용하기 어려우거나 불가능하게 만들 수 있습니다.
PublisherId를 만들려면 어떻게 해야 하나요?
PackageNameAndPublisherIdFromFamilyName 사용하여 PublisherId
에서 PackageFamilyName
를 추출하도록 합니다.
PackageIdFromFullName을 사용하여 PublisherId
에서 PackageFullName
를 추출합니다.
PublisherId
에서 Publisher
를 만들어야 하는 경우는 드물게 필요하더라도, 사용 가능한 API를 활용하여 만들 수 있습니다.
#include <appmodel.h>
HRESULT PublisherIdFromPublisher(
_In_ PCWSTR publisher,
_Out_writes_(PACKAGE_PUBLISHERID_MAX_LENGTH + 1) PWSTR publisherId)
{
PCWSTR name{ L"xyz" };
const size_t nameLength{ ARRAYSIZE(L"xyz") - 1 };
const size_t offsetToPublisherId{ name + 1 }; // xyz_...publisherid...
PACKAGE_ID id{};
id.name = name;
id.publisher = publisher;
WCHAR familyName[PACKAGE_PUBLISHERID_MAX_LENGTH + 1]{};
UINT32 n{ ARRAYSIZE(familyName) };
RETURN_IF_WIN32_ERROR(PackageFamilyNameFromId(&id, &n, familyName);
RETURN_IF_FAILED(StringCchCopyW(publisherId, PACKAGE_PUBLISHERID_MAX_LENGTH + 1, familyName + offsetToPublisherId));
return S_OK;
}
다음은 동일한 작업의 클래식 Windows C 구현입니다.
#include <appmodel.h>
HRESULT PublisherIdFromPublisher(
_In_ PCWSTR publisher,
_Out_writes_(PACKAGE_PUBLISHERID_MAX_LENGTH + 1) PWSTR publisherId)
{
const WCHAR c_name[]{ L"xyz" };
const UINT32 c_nameLength{ ARRAYSIZE(c_nameForPublisherToPublisherId) - 1 };
PACKAGE_ID id{};
id.name = c_name;
id.publisher = publisher;
WCHAR familyName[PACKAGE_PUBLISHERID_MAX_LENGTH + 1]{};
UINT32 n{ ARRAYSIZE(familyName) };
RETURN_IF_WIN32_ERROR(PackageFamilyNameFromId(&id, &n, familyName));
RETURN_IF_FAILED(StringCchCopyW(publisherId, PACKAGE_PUBLISHERID_MAX_LENGTH + 1, familyName + c_nameLength + 1);
return S_OK;
}
이렇게 하면 패키지 ID가 형식 xyz_<publisherid>
에 맞는 패키지 패밀리 이름으로 변환되어 PublisherId가 생성됩니다. 이 조리법은 안정적이고 신뢰할 수 있습니다.
이 작업을 수행하려면 SDK에서 appmodel.h로 컴파일하고 kernel32.lib와 연결하십시오(또는 API 집합을 사용하는 경우 kernelbase.lib, onecore.lib, api-ms-win-appmodel-runtime-l1.lib와 연결하십시오).
패키지 ID의 프로세서 아키텍처 이해
일반적인 오해는 패키지에 x64 코드만 포함할 수 있다는 Architecture=x64
것입니다. 이것은 사실이 아닙니다. 즉, 패키지는 x64 코드를 지원하는 시스템에서 작동하며 x64 앱에서 사용할 수 있습니다. x86, Arm 및 Windows 10 Arm64 시스템에서는 x64를 지원하지 않기 때문에 PDF 파일만 포함하는 패키지를 만들 수도 있지만, 이 패키지는 x64 호환 시스템에만 설치하도록 <Identity Architecture=x64...>
로 선언해야 합니다(예: x64 패키지는 x64 및 Windows 11에서 Arm64 시스템에만 설치할 수 있습니다).
void Encrypt(...)
{
HANDLE h{};
if (GetCpu() == arm64)
{
h = LoadLibrary(GetCurrentPackagePath() + "\bin\encrypt-arm64.dll")
p = GetProcAddress(h, "Encrypt")
return (*p)(...)
}
else
{
// ...call other implementation...
}
}
또는 여러 변형을 사용하여 중립 패키지를 만들 수 있습니다.
\
bin\
encrypt-x86.dll
encrypt-x64.dll
encrypt-arm.dll
encrypt-arm64.dll
그런 다음 개발자는 런타임 시 그들의 프로세스에 적합한 이진 파일을 LoadLibrary("bin\encrypt-" + cpu + ".dll")
을 통해 가져올 수 있습니다.
일반적으로 중립 패키지에는 아키텍처별 콘텐츠가 없지만 사용할 수 있습니다. 수행할 수 있는 작업에는 제한이 있습니다(예: x86 + x64 + arm + arm64용으로 컴파일된 notepad.exe을 포함하는 메모장 패키지를 만들 수 있지만, appxmanifest.xml는 그 중 하나만 가리키도록 <Application Executable=...>
를 선언할 수 있습니다). 필요한 부분만 설치할 수 있는 번들이 있다는 점을 감안할 때, 이는 흔치 않은 일입니다. 그것은 불법이 아니며, 단지 고급스럽고 이국적이다.
Architecture=x86
또한 (또는 x64|arm|arm64) 패키지에 지정된 아키텍처에 대한 실행 코드만 포함되는 것은 아닙니다. 그것은 단지 압도적으로 일반적인 경우입니다.
비고
이 컨텍스트에서 "코드" 또는 "실행 코드"에 대해 논의할 때 PE(이식 가능한 실행 파일) 파일을 참조합니다.
패키지 ID는 대/소문자를 구분합니까?
대부분, 아니요, 하지만 Publisher
는 대/소문자를 구분합니다.
나머지 필드(Name
, ResourceId
, PublisherId
PackageFullName
및PackageFamilyName
)는 그렇지 않습니다. 이러한 필드는 대/소문자를 유지하지만 대/소문자를 구분하지 않고 비교합니다.
참고하십시오
패키지 ID
packageFamilyNameFromId
Windows developer