필요한 일이 생겨서 간단히 프로토타이핑한 구글 수익보고서 다운로드하는 java프로그램
필요 라이브러리(아래 google-api-services-storage외에도 import된 라이브러리 추가 필요)
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-storage</artifactId>
<version>v1-rev171-1.25.0</version>
</dependency>
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.store.DataStoreFactory;
import com.google.api.services.storage.Storage;
import com.google.api.services.storage.StorageScopes;
import com.google.api.services.storage.model.Objects;
import com.google.api.services.storage.model.StorageObject;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
/**
* 구글 재무보고서 중에서 '수익'보고서를 다운로드하는 샘플 프로그램
* - 참고: https://support.google.com/googleplay/android-developer/answer/6135870#zippy=%2C%EC%88%98%EC%9D%B5
* - 2021년 11월 기준 구글스토어에서 제공하는 재무보고서는 3가지가 존재
* 1. 예상 판매실적
* 2. 수익
* 3. 대한민국 Play 잔액 차감
*
* - 추가 참고사항
* 1) 수익 보고서를 사용하여 판매 대금과 거래 내역를 파악할 수 있습니다.
* 보고서의 각 행은 거래 유형(예: 고객에게 대금을 청구하거나 Google에 수수료를 지급하는 시기)과 함께 원래 금액 및 변환된 금액을 나타냅니다.
* 2) 수익 보고서에는 이전 달에 발생한 인보이스가 포함됩니다. 최소 지급액에 도달하면 인보이스를 받게 됩니다. 수익 보고서를 사용할 수 있게 되면 몇 주 후에판매 대금을 수령할 수 있습니다.
* 3) 수익 보고서는 한 달에 한 번 생성되며 일반적으로 다음 달 5일에 제공됩니다.
* 경우에 따라 Google에서 계산 오류를 바로잡기 위해 수익을 조정할 수 있습니다.
* 이 경우 Google에서 문제에 관해 알려 드리며 개발자 기록용으로 조정된 거래만 포함되어 있는 추가 수입 파일을 생성합니다.
* 4) Google은 유럽 경제 지역(EEA)의 사용자에게 판매되는 상품의 등록된 판매자이므로, 영향을 받는 국가에서 이루어진 판매가 주문당 한 줄씩 표시됩니다.
* 또한 거래 유형은 '청구'로 표시됩니다. 다른 국가에서 이루어진 판매에는 'Google 수수료' 거래 유형도 포함됩니다.
* 5) 수익 보고서에는 지불 거절이 포함되지 않습니다
*
* @author eomsh
*/
@Slf4j
public class GetEarningsReport {
final static String encStoredCredential = "입력필요";
final static String encClientSecretJson = "입력필요";
//다운로드 저장 디렉토리 경로
final static String saveDirStr = "c:\\temp\\google_earnigns";
//버킷
final static String BUCKET_NAME = "pubsite_prod_rev_블라블라"; //버킷명(Google Play Console -> 보고서 다운로드 -> 재무 -> Cloud Storage URI복사를 통해서 확인 가능)
//수익보고서 object name
final static String OBJECT_NAME = "earnings/earnings_블라블라.zip"; //object name 샘플. earnings/earnings_202110_블라블라숫자-숫자.zip
public static void main(String[] args) throws Exception {
LocalDateTime start = LocalDateTime.now();
log.info("\n\n==== Start: {} ====", start);
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
//@formatter:off
Credential credential = authorize(
httpTransport,
jsonFactory,
new CustomByteDataStoreFactory(GoogleAuthUtils.getDecStoredCredential(encStoredCredential)),
GoogleClientSecrets.load(jsonFactory,
new StringReader(GoogleAuthUtils.getDecClientSecretsJson(encClientSecretJson)))
);
//@formatter:on
final String surfixAppVer = ".0.0.1"; //ApplicationName을 관리할때 버전을 추가하여 관리하기 위함.
final String applicationName = "블라블라" + surfixAppVer;
Storage storage = new Storage.Builder(httpTransport, jsonFactory, credential).setApplicationName(applicationName).build();
Storage.Objects.Get getObject = storage.objects().get(BUCKET_NAME, OBJECT_NAME);
final StorageObject storageObject = getObject.execute();
log.info("storageObject 정보 ==>\n\t{}", storageObject.toPrettyString());
FileUtils.forceMkdir(new File(saveDirStr)); //디렉토리 생성
log.info("저장 디렉토리:{}", saveDirStr);
String objectNameSplitArray[] = StringUtils.split(OBJECT_NAME, "/");
String saveFileFullPathStr = saveDirStr + File.separator + objectNameSplitArray[1];
log.info("저장 파일 full path:{}", saveFileFullPathStr);
final File saveFile = new File(saveFileFullPathStr);
FileUtils.deleteQuietly(saveFile); //기존 다운로드된 파일이 존재할 수 있어서 선 삭제 진행
FileOutputStream out = new FileOutputStream(saveFile);
getObject.getMediaHttpDownloader().setDirectDownloadEnabled(true); //true 설정 필요
getObject.executeMediaAndDownloadTo(out);
LocalDateTime end = LocalDateTime.now();
log.info("\n\n==== End: {} ==== 소요시간: {}(second)", end, Duration.between(start, end).getSeconds());
}
/**
* Storage의 object들 중에서, name prefix로 필터링하여 가져옴
*
* @param storage
* @param bucketName
* @param namePrefix
* @return
* @throws IOException
*/
public static Iterable<StorageObject> listObject(Storage storage, String bucketName, String namePrefix) throws IOException {
List<List<StorageObject>> pagedList = Lists.newArrayList();
Storage.Objects.List listObjects = storage.objects().list(bucketName).setPrefix(namePrefix);
Objects objects;
do {
objects = listObjects.execute();
List<StorageObject> items = objects.getItems();
if (items != null) {
pagedList.add(objects.getItems());
}
listObjects.setPageToken(objects.getNextPageToken());
} while (objects.getNextPageToken() != null);
return Iterables.concat(pagedList);
}
/**
* 구글 인증
*
* @param httpTransport
* @param jsonFactory
* @param dataStoreFactory
* @param clientSecrets
* @return
* @throws Exception
*/
public static Credential authorize(
//@formatter:off
HttpTransport httpTransport,
JsonFactory jsonFactory,
DataStoreFactory dataStoreFactory,
GoogleClientSecrets clientSecrets
//@formatter:on
) throws Exception {
if (clientSecrets.getDetails().getClientId() == null || clientSecrets.getDetails().getClientSecret() == null) {
throw new Exception("client_secrets not well formed.");
}
//@formatter:off
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow
.Builder(
httpTransport,
jsonFactory,
clientSecrets,
Collections.singleton(StorageScopes.DEVSTORAGE_FULL_CONTROL)
).setDataStoreFactory(dataStoreFactory)
.build();
//@formatter:on
return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
}
}
'JAVA > Java 일반' 카테고리의 다른 글
java stream을 이용한 정렬 (0) | 2022.01.10 |
---|---|
대용량 처리시 부하분산을 위한 데이터 분할 처리(간략) (0) | 2021.12.10 |
구글 수익 레포트 CSV파일 파싱 프로그램(Parsing Google earnings report csv file) (0) | 2021.11.18 |
java timeZone변경(PST->KST 또는 PDT->KST) 샘플 소스 (0) | 2021.11.16 |
CSV파일을 읽어서 파싱하여 DB(Mysql)에 저장하는 프로그램 샘플 (0) | 2021.11.12 |