메뉴 건너뛰기

모바일앱


공개된 것들중 가장 최근의 방식으로 인증 받고 구글 스프레드 시트 API를 사용하는 방법을 정리해 봤습니다.


1. 가장 먼저 구글 개발자 콘솔에 접속하고 로그인 하세요. 구글개발자 콘솔 가기 >


2. 좌측의 API 관리자 메뉴에서 "사용자 인증 정보" 클릭


3. 사용자 인증정보 만들기 > 서비스 계정 키 > App Engine Default Service account 를 선택합니다.


4. 키 유형을 P12로 선택합니다.


5. 생성 클릭!


6. 생성된 P12 파일을 다운로드 받습니다. (마찬가지로 JSON을 선택해서 5와 6의 과정을 반복합니다.)


7. 해당 파일중 *.P12파일만 "abcd.p12"로 이름을 변경한 후 res/raw 디렉토리 아래에 복사합니다. (raw 디렉토리가 없으면 당황말고 맹그세요^^)


8. build.gradle 파일의 dependencies 항목에 아래 내용을 추가합니다.

compile('com.google.gdata:core:1.47.1') {
        exclude group: 'com.google.guava', module: 'guava'
    }
    compile 'com.google.apis:google-api-services-oauth2:v2-rev109-1.21.0'

9.  CellAddress.java 파일을 아래와 같이 작성합니다.
public class CellAddress {
    public final int row;
    public final int col;
    public final String idString;

    /**
     * Constructs a CellAddress representing the specified {@code row} and
     * {@code col}.  The idString will be set in 'RnCn' notation.
     */
    public CellAddress(int row, int col) {
        this.row = row;
        this.col = col;
        this.idString = String.format("R%sC%s", row, col);
    }
}

10. 아래는 공유되어 있는 시트들 중 첫번째 시트를 선택해서 내용을 채워 넣는 예제 입니다. 

public class GunmanClient  {
    private Context context;
    public GunmanClient(Context context) {
        this.context = context;
    }

    //다운로드 했던 p12 파일의 내용을 리소스로 부터 읽어 파일로 생성합니다.
    private File getTempPkc12File() throws IOException {
        //InputStream pkc12Stream = context.getAssets().open("raw/abcd.p12");
        InputStream pkc12Stream = context.getResources().openRawResource(R.raw.cre);
        File tempPkc12File = File.createTempFile("temp_pkc12_file", "p12");
        OutputStream tempFileStream = new FileOutputStream(tempPkc12File);

        int read = 0;
        byte[] bytes = new byte[1024];
        while ((read = pkc12Stream.read(bytes)) != -1) {
            tempFileStream.write(bytes, 0, read);
        }
        return tempPkc12File;
    }

    // p12파일을 인증과정에 사용합니다.
    private GoogleCredential getAuth() throws IOException, GeneralSecurityException {
        HttpTransport httpTransport = new NetHttpTransport();
        JacksonFactory jsonFactory = new JacksonFactory();
        String[] SCOPESArray = {"https://spreadsheets.google.com/feeds", "https://spreadsheets.google.com/feeds/spreadsheets/private/full", "https://docs.google.com/feeds"};
        final List SCOPES = Arrays.asList(SCOPESArray);
        GoogleCredential credential = new GoogleCredential.Builder()
                .setTransport(httpTransport)
                .setJsonFactory(jsonFactory)
                // 11번 순서로 부터 얻은 client_email 의 값을 반영합니다
                .setServiceAccountId("xxxxxxx@appspot.gserviceaccount.com")
                .setServiceAccountScopes(SCOPES)
                .setServiceAccountPrivateKeyFromP12File(getTempPkc12File())
                .build();

        return credential;
    }

    private Map<String, CellEntry> getCellEntryMap(
            SpreadsheetService ssSvc, URL cellFeedUrl, List<CellAddress> cellAddrs)
            throws IOException, ServiceException {
        CellFeed batchRequest = new CellFeed();
        for (CellAddress cellId : cellAddrs) {
            CellEntry batchEntry = new CellEntry(cellId.row, cellId.col, cellId.idString);
            batchEntry.setId(String.format("%s/%s", cellFeedUrl.toString(), cellId.idString));
            BatchUtils.setBatchId(batchEntry, cellId.idString);
            BatchUtils.setBatchOperationType(batchEntry, BatchOperationType.QUERY);
            batchRequest.getEntries().add(batchEntry);
        }

        CellFeed cellFeed = ssSvc.getFeed(cellFeedUrl, CellFeed.class);
        CellFeed queryBatchResponse =
                ssSvc.batch(new URL(cellFeed.getLink(Link.Rel.FEED_BATCH, Link.Type.ATOM).getHref()),
                        batchRequest);

        Map<String, CellEntry> cellEntryMap = new HashMap<>(cellAddrs.size());
        for (CellEntry entry : queryBatchResponse.getEntries()) {
            cellEntryMap.put(BatchUtils.getBatchId(entry), entry);
        }

        return cellEntryMap;
    }

    //데이터가 담긴 리스트의 내용들 WORKSHEET에 씁니다
    public boolean addDataToSheetList(ArrayList<String> myData, ProgressDialog progress) throws IOException, ServiceException, GeneralSecurityException {
        SpreadsheetService service =
                new SpreadsheetService("MySpreadsheetIntegration");
        service.setProtocolVersion(SpreadsheetService.Versions.V3);
        service.setOAuth2Credentials(getAuth());

        // Define the URL to request.  This should never change.
        URL SPREADSHEET_FEED_URL = new URL("https://spreadsheets.google.com/feeds/spreadsheets/private/full");

        // Make a request to the API and get all spreadsheets.
        SpreadsheetFeed feed = service.getFeed(SPREADSHEET_FEED_URL, SpreadsheetFeed.class);
        List<SpreadsheetEntry> spreadsheets = feed.getEntries();
        // Iterate through all of the spreadsheets returned

        boolean isSuccess = true;

        // 공유되어 있는 스프레드 시트중 첫번째 시트를 획득합니다
        SpreadsheetEntry spreadsheet = spreadsheets.get(0);

        //for (SpreadsheetEntry spreadsheet : spreadsheets) {
            // Print the title of this spreadsheet to the screen
            Log.d("GUNMAN", spreadsheet.getTitle().getPlainText());
            WorksheetFeed worksheetFeed = service.getFeed(spreadsheet.getWorksheetFeedUrl(), WorksheetFeed.class);
            List<WorksheetEntry> worksheets = worksheetFeed.getEntries();
            WorksheetEntry worksheet = worksheets.get(0);

            URL cellFeedUrl = worksheet.getCellFeedUrl();
            CellFeed cellFeed = service.getFeed(cellFeedUrl, CellFeed.class);

            // Build list of cell addresses to be filled in
            List<CellAddress> cellAddrs = new ArrayList<CellAddress>();
            for (int row = 1; row <= myData.size(); ++row) {
                //for (int col = 1; col <= 3; ++col) {
                    cellAddrs.add(new CellAddress(row, col));
                //}
            }

            // Prepare the update
            // getCellEntryMap is what makes the update fast.
            Map<String, CellEntry> cellEntries = getCellEntryMap(service, cellFeedUrl, cellAddrs);

            CellFeed batchRequest = new CellFeed();


            int i = 0;
            int prog=0;
            for(String element : myData) {
                CellAddress cellAddr = cellAddrs.get(i);
                CellEntry batchEntry = new CellEntry(cellEntries.get(cellAddr.idString));
                batchEntry.changeInputValueLocal(element);
                BatchUtils.setBatchId(batchEntry, cellAddr.idString);
                BatchUtils.setBatchOperationType(batchEntry, BatchOperationType.UPDATE);
                batchRequest.getEntries().add(batchEntry);

                i++;
            }

            // Submit the update
            Link batchLink = cellFeed.getLink(Link.Rel.FEED_BATCH, Link.Type.ATOM);
            CellFeed batchResponse = service.batch(new URL(batchLink.getHref()), batchRequest);

            // Check the results
            for (CellEntry entry : batchResponse.getEntries()) {
                //String batchId = BatchUtils.getBatchId(entry);
                if (!BatchUtils.isSuccess(entry)) {
                    isSuccess = false;
                    BatchStatus status = BatchUtils.getBatchStatus(entry);
                }
            }
        //}


        return isSuccess;
    }
}


11. 다운로드 받은 JSON 파일을 에디터에서 열어 "client_email"에 해당하는 "xxxx@appspot.googleservices.com" 주소를 확인합니다. (복사)


12. 구글 스프레드 시트를 하나 생성한 후 11에서 얻은 이메일 주소에 공유합니다.


13. 지금까지 작성한 코드를 실행해서 테스트 해 봅니다 ㅎ


건투를 빕니다~!!




번호 제목 글쓴이 날짜 조회 수
공지 [TIP] 안드로이드 앱 빌드시 "Error:Execution failed for task ':app:compileDebugJavaWithJavac'" 오류가 발생할 경우 파이팅건맨 2017.09.13 7219
공지 [TIP] 죽지 않는 안드로이드 서비스 만들기 (Unstoppable service) [6] 파이팅건맨 2015.06.26 6642
공지 [TIP] 안드로이드 앱이 처음 설치될때 Referrer 정보 받아 오기 파이팅건맨 2016.08.30 3725
44 tizen .net wearable widget 질문해도 될까요? [1] 갤럭시규 2019.08.19 21
43 [TIP] iOS - UIWebView에 로컬 html 파일 로드하기 (Swift 4) 파이팅건맨 2019.06.05 77
42 [TIP] Tizen Push가 갑자기 내려오지 않을때 파이팅건맨 2019.05.20 43
41 [TIP] 두근두근앱이 라즈베리파이를 두근거리도록 개발한 기록 #3 파이팅건맨 2019.05.15 176
40 [TIP] 두근두근앱이 라즈베리파이를 두근거리도록 개발한 기록 #2 파이팅건맨 2019.05.11 184
39 [TIP] Android 코드에서 블루투스 연결이 잘 안될때 파이팅건맨 2019.05.11 266
38 [TIP] 두근두근앱이 라즈베리파이를 두근거리도록 개발한 기록 #1 파이팅건맨 2019.05.07 273
37 [TIP] 타이젠 스튜디오에서 웨어러블 디바이스로 디버깅을 위한 바이너리 전송이 안 될때 파이팅건맨 2019.03.26 176
36 [TIP] http://tizen.org/system/tizenid 으로 타이젠 고유 id를 확보할 때 유의할 점 파이팅건맨 2019.03.14 83
35 [TIP] "cordova run android" 명령을 실행했는데 "A problem occurred evaluating project ':CordovaLib'"오류가 뜰때 파이팅건맨 2019.01.22 331
34 [TIP] Mac에서 Cordova run android 를 실행했는데 "Command failed with exit code EACCES" 오류가 뜰때 파이팅건맨 2019.01.22 159
33 [TIP] 안드로이드에서 심박수 측정하는 코드 [6] 파이팅건맨 2019.01.02 651
32 [TIP] Google Cloud API 사용시 안드로이드의 Assets 폴더에 있는 Crendential 파일 사용하기 파이팅건맨 2018.05.29 238
31 [TIP] 안드로이드 스튜디오에서 Error:android-apt plugin is incompatible with the Android Gradle plugin. Please use 'annotationProcessor' configuration instead 오류날때 파이팅건맨 2018.02.02 2058
30 [TIP] 안드로이드 앱 빌드시 "Error:Execution failed for task ':app:compileDebugJavaWithJavac'" 오류가 발생할 경우 파이팅건맨 2017.09.13 7219
29 [TIP] Error:java.lang.OutOfMemoryError: GC overhead limit exceeded 파이팅건맨 2016.11.03 889
28 [TIP] 안드로이드 앱이 처음 설치될때 Referrer 정보 받아 오기 파이팅건맨 2016.08.30 3725
» [TIP] 안드로이드에서 구글 스프레드시트에 데이터 쓰기 파이팅건맨 2016.05.04 2496
26 [TIP] 안드로이드에서 키보드가 나타날 때 레이아웃이 위로 움직인다면 파이팅건맨 2016.03.22 852
25 [TIP] 안드로이드 - 설치된 앱 목록 얻기 파이팅건맨 2016.03.22 3166
위로