我在iOS上实现savedgame。
https://developers.google.com/games/services/cpp/savedgames
但无法保存快照,前提是在Google Play控制台上启用保存的游戏并成功登录过程。
2016-03-19 20:27:15.512 Ojichu[6912:2130626] Creating new snapshot
2016-03-19 20:27:28.106 Ojichu[6912:2130626] new snapshot name is: ojimon_19700101090000
2016-03-19 20:27:28.107 Ojichu[6912:2130626] Saving Snapshot ojimon_19700101090000
2016-03-19 20:27:28.107 Ojichu[6912:2130626] desc
2016-03-19 20:27:28.108 Ojichu[6912:2130626] ERROR: Invalid filename ojimon_19700101090000: not opening.
2016-03-19 20:27:28.116 Ojichu[6912:2130626] Creating new snapshot
2016-03-19 20:27:35.164 Ojichu[6912:2130626] new snapshot name is: ojimon_19700101090000
2016-03-19 20:27:35.165 Ojichu[6912:2130626] Saving Snapshot ojimon_19700101090000
2016-03-19 20:27:35.166 Ojichu[6912:2130626] desc
2016-03-19 20:27:35.166 Ojichu[6912:2130626] ERROR: Invalid filename ojimon_19700101090000: not opening.
2016-03-19 20:27:37.632 Ojichu[6912:2130626] ERROR_INTERNAL
2016-03-19 20:27:41.663 Ojichu[6912:2130626] ERROR_INTERNAL
2016-03-19 20:27:41.664 Ojichu[6912:2131093] VERBOSE: Snapshot cache fully expired: refreshing all.
2016-03-19 20:27:43.590 Ojichu[6912:2131155] VERBOSE: Download file request: <NSMutableURLRequest: 0x175612630> { URL: https://doc-10-5c-docs.googleusercontent.com/docs/securesc/33he8l9b76c43lgcbshrpvv8v4q7ph0p/h1d7ha0sijr8a0afqi58e1vk50sb1c0d/1458381600000/14598062468829450291/14598062468829450291/1MBK837eoIA8e6iQ4iYtRW-cNgLJCXDGUb7ntuIxfqO__SOPtJjYI_ubJzQuyCbBjo7zYxsk?e=download&gd=true }
2016-03-19 20:27:43.591 Ojichu[6912:2131155] VERBOSE: Download file response: <NSHTTPURLResponse: 0x17623dfc0> { URL: https://doc-10-5c-docs.googleusercontent.com/docs/securesc/33he8l9b76c43lgcbshrpvv8v4q7ph0p/h1d7ha0sijr8a0afqi58e1vk50sb1c0d/1458381600000/14598062468829450291/14598062468829450291/1MBK837eoIA8e6iQ4iYtRW-cNgLJCXDGUb7ntuIxfqO__SOPtJjYI_ubJzQuyCbBjo7zYxsk?e=download&gd=true } { status code: 200, headers {
"Access-Control-Allow-Origin" = "*";
"Cache-Control" = "private, max-age=0";
"Content-Disposition" = "attachment;filename=\"save_19700101090000\";filename*=UTF-8''save_19700101090000";
"Content-Length" = 0;
"Content-Type" = "application/vnd.google-play-games.snapshot-initial";
Date = "Sat, 19 Mar 2016 11:27:43 GMT";
Expires = "Sat, 19 Mar 2016 11:27:43 GMT";
Server = UploadServer;
"access-control-allow-credentials" = false;
"access-control-allow-headers" = "Accept, Accept-Language, Authorization, Cache-Control, Content-Disposition, Content-Encoding, Content-Language, Content-Length, Content-MD5, Content-Range, Content-Type, Date, GData-Version, Host, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, Origin, OriginToken, Pragma, Range, Slug, Transfer-Encoding, Want-Digest, X-ClientDetails, X-GData-Client, X-GData-Key, X-Goog-AuthUser, X-Goog-PageId, X-Goog-Encode-Response-If-Executable, X-Goog-Correlation-Id, X-Goog-Request-Info, X-Goog-Experiments, x-goog-iam-authority-selector, x-goog-iam-authorization-token, X-Goog-Spatula, X-Goog-Upload-Command, X-Goog-Upload-Content-Disposition, X-Goog-Upload-Content-Length, X-Goog-Upload-Content-Type, X-Goog-Upload-File-Name, X-Goog-Upload-Offset, X-Goog-Upload-Protocol, X-Goog-Visitor-Id, X-HTTP-Method-Override, X-JavaScript-User-Agent, X-Pan-Versionid, X-Origin, X-Referer, X-Upload-Content-Length, X-Upload-Content-Type, X-Use-HTTP-Status-Code-Override, X-YouTube-VVT, X-YouTube-Page-CL, X-YouTube-Page-Timestamp";
"access-control-allow-methods" = "GET,OPTIONS";
"alt-svc" = "quic=\":443\"; ma=2592000; v=\"31,30,29,28,27,26,25\"";
"alternate-protocol" = "443:quic,p=1";
"x-guploader-uploadid" = "AEnB2Urbfr6ZC5ugHKhy7J4rRs991A5BWbqobZzKEBPRBIhnY-fL5j4dGLouLw60b1URXquBsNm-1LTP0FRM-aGxqN9Vh-OVWg";
} }
2016-03-19 20:27:43.593 Ojichu[6912:2131155] VERBOSE: Download file file name: /var/mobile/Containers/Data/Application/3FC79FFD-1D7A-4827-9A62-08FDD8B15361/Library/Application Support/jp.usaya.Ojichu/snapshots/fe3b73dcc261e238df050ffc3a02fe24
2016-03-19 20:27:43.599 Ojichu[6912:2131093] VERBOSE: Merging new snapshot: no entry for save_19700101090000.
2016-03-19 20:27:51.235 Ojichu[6912:2130626] ERROR_INTERNAL
我的代码在
下面/* Copyright (c) 2014 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "StateManager.h"
#ifdef __APPLE__
//
//Logging for CoreFoundation
//
#include <CoreFoundation/CoreFoundation.h>
extern "C" void NSLog(CFStringRef format, ...);
const int32_t BUFFER_SIZE = 256;
#define LOGI(...) {char c[BUFFER_SIZE];\
snprintf(c,BUFFER_SIZE,__VA_ARGS__);\
CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, c, kCFStringEncodingMacRoman);\
NSLog(str);\
CFRelease(str);\
}
#else
#include "android/log.h"
#define DEBUG_TAG "TeapotNativeActivity"
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, DEBUG_TAG, __VA_ARGS__))
#endif
StateManager* StateManager::_instance = nullptr;
void StateManager::onAuthActionFinished(gpg::AuthOperation op, gpg::AuthStatus status)
{
LOGI("OnAuthActionFinished");
switch (status) {
case gpg::AuthStatus::VALID:
LOGI("Signed In");
break;
case gpg::AuthStatus::ERROR_INTERNAL:
case gpg::AuthStatus::ERROR_NOT_AUTHORIZED:
case gpg::AuthStatus::ERROR_VERSION_UPDATE_REQUIRED:
case gpg::AuthStatus::ERROR_TIMEOUT:
default:
LOGI("Sign-in failure");
break;
}
}
void StateManager::onAuthActionStarted(gpg::AuthOperation op)
{
LOGI("OnAuthActionStarted");
switch (op) {
case gpg::AuthOperation::SIGN_IN:
LOGI("Signing In");
break;
case gpg::AuthOperation::SIGN_OUT:
LOGI("Signing Out");
break;
}
}
gpg::GameServices *StateManager::getGameServices()
{
return _gameServices.get();
}
void StateManager::beginUserInitiatedSignIn()
{
if (!_gameServices->IsAuthorized()) {
LOGI("StartAuthorizationUI");
_gameServices->StartAuthorizationUI();
}
}
void StateManager::signOut()
{
if (_gameServices->IsAuthorized()) {
LOGI("SignOut");
_gameServices->SignOut();
}
}
void StateManager::initServices(gpg::PlatformConfiguration &pc)
{
LOGI("Initializing Services");
LOGI(pc.Valid()? "configuration is valid":"configuration is invalid");
if (!_gameServices) {
LOGI("Uninitialized services, so creating");
_gameServices = gpg::GameServices::Builder()
.SetOnAuthActionStarted([this]( gpg::AuthOperation op ){
LOGI("Sign in started");
this->onAuthActionStarted(op);
})
.SetOnAuthActionFinished([this](gpg::AuthOperation op, gpg::AuthStatus status){
LOGI("Sign in finished with a result of %d", status);
_isSignedIn = status == gpg::AuthStatus::VALID;
this->onAuthActionFinished(op, status);
})
.SetDefaultOnLog(gpg::LogLevel::VERBOSE)
.EnableSnapshots()
.Create(pc);
}
LOGI("Created");
}
void StateManager::committedSnapshot(gpg::SnapshotManager::CommitResponse const & response)
{
switch (response.status) {
case gpg::ResponseStatus::VALID:
LOGI("Snapshot CommitResponse VALID");
break;
case gpg::ResponseStatus::VALID_BUT_STALE:
LOGI("Snapshot CommitResponse VALID_BUT_STALE");
break;
case gpg::ResponseStatus::ERROR_LICENSE_CHECK_FAILED:
LOGI("Snapshot CommitResponse ERROR_LICENSE_CHECK_FAILED");
break;
case gpg::ResponseStatus::ERROR_INTERNAL:
LOGI("Snapshot CommitResponse ERROR_INTERNAL");
break;
case gpg::ResponseStatus::ERROR_NOT_AUTHORIZED:
LOGI("Snapshot CommitResponse ERROR_NOT_AUTHORIZED");
break;
case gpg::ResponseStatus::ERROR_VERSION_UPDATE_REQUIRED:
LOGI("Snapshot CommitResponse ERROR_VERSION_UPDATE_REQUIRED");
break;
case gpg::ResponseStatus::ERROR_TIMEOUT:
LOGI("Snapshot CommitResponse ERROR_TIMEOUT");
break;
default:
break;
}
}
void StateManager::loadedSnapshot(gpg::SnapshotManager::ReadResponse const & response)
{
switch (response.status) {
case gpg::ResponseStatus::VALID:
LOGI("Snapshot CommitResponse VALID");
break;
case gpg::ResponseStatus::VALID_BUT_STALE:
LOGI("Snapshot CommitResponse VALID_BUT_STALE");
break;
case gpg::ResponseStatus::ERROR_LICENSE_CHECK_FAILED:
LOGI("Snapshot CommitResponse ERROR_LICENSE_CHECK_FAILED");
break;
case gpg::ResponseStatus::ERROR_INTERNAL:
LOGI("Snapshot CommitResponse ERROR_INTERNAL");
break;
case gpg::ResponseStatus::ERROR_NOT_AUTHORIZED:
LOGI("Snapshot CommitResponse ERROR_NOT_AUTHORIZED");
break;
case gpg::ResponseStatus::ERROR_VERSION_UPDATE_REQUIRED:
LOGI("Snapshot CommitResponse ERROR_VERSION_UPDATE_REQUIRED");
break;
case gpg::ResponseStatus::ERROR_TIMEOUT:
LOGI("Snapshot CommitResponse ERROR_TIMEOUT");
break;
default:
break;
}
}
void StateManager::selectedSnapshot(gpg::SnapshotManager::SnapshotSelectUIResponse const & response)
{
switch (response.status) {
case gpg::UIStatus::VALID:
{
if ( response.data.Valid() )
{
_currentSnapshot = response.data.FileName();
if (_gameServices)
{
LOGI("Loading Snapshot %s",_currentSnapshot.c_str());
_gameServices->Snapshots().Open(response.data.FileName(),
gpg::SnapshotConflictPolicy::LONGEST_PLAYTIME,
[this](gpg::SnapshotManager::OpenResponse const & response) {
LOGI("Reading file");
_gameServices->Snapshots().Read(response.data,
std::bind(&StateManager::loadedSnapshot, this,
std::placeholders::_1));
});
}
} else {
LOGI("Creating new snapshot");
_currentSnapshot.clear();
std::string str = "aaaaaaaaaaaa";
auto tp = std::chrono::system_clock::now();
auto d = tp.time_since_epoch();
auto m = std::chrono::duration_cast<std::chrono::milliseconds>(d);
std::vector<uint8_t> png;
std::vector<uint8_t> data(str.begin(),str.end());
saveSnapshot("desc", m, png, data);
}
break;
}
case gpg::UIStatus::ERROR_INTERNAL:
LOGI("Snapshot SelectUIResponse ERROR_INTERNAL");
break;
case gpg::UIStatus::ERROR_NOT_AUTHORIZED:
LOGI("Snapshot SelectUIResponse ERROR_NOT_AUTHORIZED");
break;
case gpg::UIStatus::ERROR_VERSION_UPDATE_REQUIRED:
LOGI("Snapshot SelectUIResponse ERROR_VERSION_UPDATE_REQUIRED");
break;
case gpg::UIStatus::ERROR_TIMEOUT:
LOGI("Snapshot SelectUIResponse ERROR_TIMEOUT");
break;
case gpg::UIStatus::ERROR_CANCELED:
LOGI("Snapshot SelectUIResponse ERROR_CANCELED");
break;
case gpg::UIStatus::ERROR_UI_BUSY:
LOGI("Snapshot SelectUIResponse ERROR_UI_BUSY");
break;
case gpg::UIStatus::ERROR_LEFT_ROOM:
LOGI("Snapshot SelectUIResponse ERROR_LEFT_ROOM");
break;
default:
break;
}
}
void StateManager::saveSnapshot(std::string description,
std::chrono::milliseconds playtime,
std::vector<uint8_t> png_data,
std::vector<uint8_t> snapData)
{
if (_gameServices)
{
//if we do not have current snapshot we generate the filename
if (_currentSnapshot.empty())
{
std::chrono::system_clock::time_point today = std::chrono::system_clock::now();
std::time_t tt = std::chrono::system_clock::to_time_t ( today );
//using strftime
time_t rawtime;
struct tm * timeinfo;
char buffer [32];
time (&tt);
timeinfo = localtime (&rawtime);
strftime (buffer,32,"save_%Y%m%d%H%M%S",timeinfo);
//put_time not available in GCC < 5.0
//std::ostringstream snapshot_name;
//snapshot_name << std::put_time(ctime(&tt),"save_%Y%m%d%H%M%S");
_currentSnapshot.assign(buffer,32);
LOGI("new snapshot name is: %s",_currentSnapshot.c_str());
}
LOGI("Saving Snapshot %s",_currentSnapshot.c_str());
LOGI("%s",description.c_str());
_gameServices->Snapshots().Open(_currentSnapshot,
gpg::SnapshotConflictPolicy::LONGEST_PLAYTIME,
[this, description, playtime, png_data, snapData](gpg::SnapshotManager::OpenResponse const &response)
{
gpg::SnapshotMetadata metadata;
if (IsSuccess(response.status)) { // Always failure
metadata = response.data;
gpg::SnapshotMetadataChange::Builder builder;
if ( description != metadata.Description())
{
builder.SetDescription(description);
}
if ( playtime != metadata.PlayedTime())
{
builder.SetPlayedTime(static_cast<gpg::Duration>(playtime));
}
if ( ! png_data.empty() )
{
builder.SetCoverImageFromPngData(png_data);
}
gpg::SnapshotMetadataChange metadata_change = builder.Create();
_gameServices->Snapshots().Commit(
metadata,
metadata_change,
snapData,
std::bind(&StateManager::committedSnapshot,this,std::placeholders::_1));
}
});
}
}
void StateManager::selectSnapshot(std::string title, uint32_t max_snapshots, bool allow_create, bool allow_delete)
{
if (_gameServices)
{
LOGI("Listing Snapshot");
LOGI("%s",title.c_str());
_gameServices->Snapshots().ShowSelectUIOperation(allow_create,
allow_delete,
max_snapshots,
title,
std::bind(&StateManager::selectedSnapshot, this,
std::placeholders::_1));
}
}
有没有人解决这个问题?