콘텐츠로 이동

Java SDK

Markdown 원문

ActivationClient로 Java 앱에 라이센스 활성화를 연결해요. SDK를 설치하고 고객 포털에서 기기를 승인한 뒤, 앱에서 기능을 사용할 수 있는지 확인하는 과정을 알아보세요.

활성화 요청은 승인할 앱 설치를 식별하는 정보예요. 고객이 해당 앱의 이름과 로고가 표시된 포털에서 소유한 라이센스를 선택하면, 그 요청과 기기에 묶인 서명된 활성화 응답을 받아요. 라이센스 하나에는 활성 기기 하나만 등록돼요.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>kr.signox.samples</groupId><artifactId>licensed-export</artifactId><version>0.3.1-SNAPSHOT</version>
<properties><maven.compiler.release>8</maven.compiler.release><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties>
<dependencies><dependency><groupId>kr.signox</groupId><artifactId>signox-sdk</artifactId><version>0.3.1-SNAPSHOT</version></dependency></dependencies>
<build><plugins>
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.13.0</version></plugin>
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-dependency-plugin</artifactId><version>3.8.1</version></plugin>
<plugin><groupId>org.codehaus.mojo</groupId><artifactId>exec-maven-plugin</artifactId><version>3.6.3</version></plugin>
</plugins></build>
</project>
Terminal window
mvn -U compile

개발 환경에 설정된 패키지 저장소를 사용하세요. SDK는 앱의 의존성으로 설치해요. 샘플 ZIP에는 실행 예제 소스가 들어 있으며, SDK 설치를 대신하지 않아요.

실행 환경: Java 8+, 예제 빌드는 JDK 17+·Maven 3.6.3+.

프로젝트 폴더에서 Maven이 선택한 SDK 버전을 확인하세요. 출력에 kr.signox:signox-sdk:jar:0.3.1-SNAPSHOT이 표시되어야 해요. JDK 설치와 SDK 의존성 설치는 별도예요.

Terminal window
mvn dependency:tree -Dincludes=kr.signox:signox-sdk

2. 제품과 테스트 라이센스를 준비하세요

섹션 제목: “2. 제품과 테스트 라이센스를 준비하세요”

벤더 대시보드에서 제품을 선택하고 설정을 여세요. 제품 상세 주소의 UUID를 확인하고 그 제품의 공개키를 내려받으세요. 정책에 demo_export 불리언 기능을 추가해 켠 뒤 테스트 라이센스를 발급하고, 고객 포털에서 테스트 고객에게 구매 키를 등록하세요.

입력얻는 위치와 사용 방법
SIGNOX_API_URL테스트할 환경의 API 주소를 사용해요. 포털 주소와는 달라요.
SIGNOX_PRODUCT_ID벤더의 제품 상세 주소에 있는 UUID예요.
SIGNOX_PUBLIC_KEY_FILE내려받은 제품 공개키 파일의 경로예요. PEM 내용 자체를 변수에 넣지 않아요.
.signox-state예제가 만드는 개인 상태 디렉터리예요. 재시작 후에도 같은 경로를 유지하세요.

예제를 실행할 셸에 위 세 환경변수를 설정하세요. 제품 공개키는 신뢰하는 앱 배포물에 포함해 사용하세요. 고객 비밀번호는 고객 포털에만 입력하고, 라이센스 키는 앱에 하드코딩하지 않아요.

아래 전체 코드를 src/main/java/App.java 파일로 저장하세요. 모든 명령은 같은 프로젝트 디렉터리에서 실행하세요.

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import kr.signox.sdk.*;
public class App {
public static void main(String[] args) throws Exception {
String api = System.getenv("SIGNOX_API_URL"), product = System.getenv("SIGNOX_PRODUCT_ID"), keyFile = System.getenv("SIGNOX_PUBLIC_KEY_FILE");
if (api == null || product == null || keyFile == null)
throw new IllegalArgumentException("Set SIGNOX_API_URL, SIGNOX_PRODUCT_ID and SIGNOX_PUBLIC_KEY_FILE");
String pem = new String(Files.readAllBytes(Paths.get(keyFile)), StandardCharsets.UTF_8);
ActivationClient client = new ActivationClient(product,
SignoxConfig.builder(pem).baseUrl(api).build(), new File(".signox-state"));
String command = args.length == 0 ? "start" : args[0];
if (command.equals("start")) System.out.println(client.start().portalUrl);
else if (command.equals("request")) System.out.println(client.createRequest());
else if (command.equals("poll")) {
ActivationClient.Progress progress = client.poll();
System.out.println(progress.status);
if (progress.result != null && !progress.result.isValid()) System.exit(2);
}
else {
LicenseResult result = command.equals("apply")
? client.applyResponse(new String(Files.readAllBytes(Paths.get(args[1])), StandardCharsets.UTF_8)) : client.validate();
boolean allowed = result.isValid() && result.getFeatureBool("demo_export", false);
System.out.println("code=" + result.getCode() + ", exportAllowed=" + allowed);
if (!result.isValid()) System.exit(2);
}
}
}

브라우저 승인과 파일 전달 모두 같은 클라이언트를 사용해요. SDK가 실행 환경의 장치 모듈을 선택하므로 앱에서 장치 공급자 종류를 고르지 않아요.

4. 고객 포털에서 기기를 승인하세요

섹션 제목: “4. 고객 포털에서 기기를 승인하세요”
Terminal window
mvn compile exec:java -Dexec.mainClass=App -Dexec.args="start"

출력된 portalUrl을 시스템 브라우저로 여세요. 앱 이름과 기기 이름을 확인한 뒤 고객 계정으로 로그인하고, 소유한 라이센스를 골라 이 기기 활성화를 누르세요. 다른 기기가 등록되어 있다면 사유를 입력해 벤더에게 이전 검토를 요청할 수 있어요.

Terminal window
mvn compile exec:java -Dexec.mainClass=App -Dexec.args="poll"

승인 전에는 status가 pending이에요. 승인 후 다시 실행하면 응답을 받아 적용해요. 3초보다 짧은 간격으로 반복 호출하지 마세요. pending은 승인 대기이며 라이센스 검증 성공이 아니에요.

5. 기능 실행 전에 권한을 확인하세요

섹션 제목: “5. 기능 실행 전에 권한을 확인하세요”
Terminal window
mvn compile exec:java -Dexec.mainClass=App -Dexec.args="status"

성공하면 VALID 또는 IN_GRACE_PERIOD가 나와요. 라이센스가 유효하고 demo_export가 true일 때만 예제의 exportAllowed가 true가 돼요. 기능이 없는 라이센스는 유효하더라도 CSV를 만들면 안 돼요. 이 판정을 시작 화면뿐 아니라 앱의 실제 내보내기 함수에도 넣으세요.

실제 CSV 파일을 만드는 샘플 실행하기

원래 기기에 연결이 없다면 요청을 내보내고, 연결된 PC의 고객 포털 /activate에서 가져오세요. 승인 후 받은 activation.signox를 원래 기기로 옮겨요. SDK의 applyResponse에는 파일 경로가 아닌 파일 내용을 전달해요. 위 예제는 대신 파일을 읽어 줘요.

Terminal window
mvn compile exec:java -Dexec.mainClass=App -Dexec.args="request"
mvn compile exec:java -Dexec.mainClass=App -Dexec.args="apply activation.signox"

파일로 전달할 때는 언어별 샘플의 activation-request request.signox 명령을 사용하세요. 특히 Maven의 빌드 로그를 요청 파일로 리다이렉션하지 마세요.

연결 없이 응답을 적용하려면 지원되고 신뢰 등록된 기기 키가 필요해요. 보호 기능이 없으면 응답 적용 시 연결해야 해요. 앱을 배포하기 전에 실행 환경과 기기 요구 사항을 확인하세요.

오프라인 실행 환경 확인하기

이름타입필수 여부·기본값설명
productIdString필수ActivationClient 생성자의 제품 UUID
configSignoxConfig필수공개키와 서버 연결 설정
stateDirFile필수이 설치에서만 쓰는 영속 디렉터리
baseUrlStringhttps://api.signox.krSignoxConfig.Builder 옵션
timeoutMsint10000 ms연결·읽기 제한 시간
tsToleranceSecondslong300 초서버 시각과의 허용 차이
offlineGraceDayslong365 일서버 통신 유예를 줄이는 로컬 상한; 0이면 캐시 유예 해제

로컬 유예 상한으로 서버가 서명한 기간을 늘릴 수는 없어요. 만료 유예와 통신 장애 유예는 별개이며, 빈 캐시로 최초 활성화를 허용하지 않아요.

신뢰하는 실행 모듈로 시험하기

섹션 제목: “신뢰하는 실행 모듈로 시험하기”

기본값은 OS에 맞는 모듈을 자동 선택해요. 통제된 기기 시험이나 앱이 직접 제공하는 모듈을 사용할 때는 new ActivationClient(productId, config, stateDir, executable, args...)을 지정할 수 있어요. 신뢰하는 앱 배포물이나 시험 환경에서 제공한 실행 파일만 사용하세요. 고객 요청 JSON이나 활성화 응답의 경로를 실행하면 안 돼요. 샘플은 제공된 시험용 래퍼를 SIGNOX_OFFLINE_RUNTIME·SIGNOX_OFFLINE_EXECUTABLE로 지정할 수 있어요. 이 옵션으로 기기 신뢰와 서명 검증을 우회하지는 않아요.

시그니처반환 타입동작
start()ActivationClient.Session요청을 등록하고 브라우저 주소와 요청 번호를 반환해요.
createRequest() / createRequest(name, renew)String공개 요청 JSON을 반환해요. name은 기기 표시명, renew는 설치 자격증명을 유지한 새 요청 생성 여부예요.
poll()ActivationClient.Progress승인 전에는 pending, 승인 후에는 응답을 적용한 검증 결과를 반환해요.
applyResponse(content)LicenseResult응답 문자열을 읽고 요청·기기 일치를 검증한 뒤 적용해요.
validate()LicenseResult라이센스 상태와 현재 기능 권한을 확인해요.
deactivate()LicenseResult연결 기반 등록을 해제해요. 보호된 이용권은 이전 검토로 안내해요.

Node는 비동기 메서드예요. Java·C#·Python은 동기 메서드이므로 네트워크·장치 작업을 UI 스레드 밖에서 실행하세요. LicenseResult에는 유효 여부·코드·기능값이 들어 있어요. 요청·상태·가져오기 오류의 예외를 검증 성공으로 바꾸면 안 돼요.

현상·코드원인조치와 재확인 결과
STATE_INVALID저장한 설치 상태가 없거나 손상됨보존한 상태를 복원하세요. 복구할 수 없으면 새 설치에서 요청을 만들어 이전을 신청하세요.
DEVICE_TRUST_REQUIRED검증되지 않은 장비 키에는 포털이 발급할 수 없음운영자가 실제 기기의 키를 별도 신뢰 경로로 대조하고 등록한 뒤 다시 승인하세요.
TRANSFER_REQUIRED다른 기기가 등록되어 있거나 보호된 반납을 확인할 수 없음새 기기의 요청으로 이전을 신청하세요. 벤더는 그 요청을 검토해요.
ACTIVATION_RESPONSE_INVALID다른 파일·서명·요청·기기원래 기기에서 이 요청에 발급된 응답을 적용하세요. 응답 내용을 수정하지 마세요.
REQUEST_EXPIRED요청의 7일 유효기간 경과새 요청을 만들어 고객 승인을 다시 진행하세요.
NETWORK_ERROR일시적인 연결·서비스 장애연결을 복구하세요. 기존의 유효한 서명 이용권·캐시만 연결 없이 사용할 수 있어요.
REQUEST_ERROR잘못된 주소·입력·접근 권한요청을 수정하세요. 영구 HTTP 오류를 무한 재시도하지 마세요.

서명된 정지·폐기·만료 거절을 받은 뒤 연결이 끊겨도 거절을 유지해야 해요. 이전 오프라인 이용권으로 덮지 마세요. 계속 연결되지 않은 기기는 즉시 원격 회수 신호를 받을 수 없으며, 포맷이나 파일 삭제만으로 옛 백업이 중단됐다고 증명할 수 없어요.

통합 검증 실행하기 · 기기 복구·이전 알아보기

응답은 받았지만 로컬 검증에 실패하면 polling의 status는 application_failed이고 result는 무효예요. applied와 유효한 result를 함께 확인해야 적용 성공이에요.

요청 생성과 적용에 같은 실행 모듈 설정을 사용하세요. 브라우저·파일 전달 방식은 기기 보호 유무를 선택하는 옵션이 아니고, 요청 이름을 바꾸어도 공급자가 바뀌지 않아요. 검증된 응답에서 OFFLINE_NOT_SUPPORTED가 나오면 필요한 로컬 실행 모듈을 사용할 수 없는 상태이므로 기존 환경을 복원하세요. 무조건 새 신뢰 등록을 요청하는 오류는 아니에요.