Cocos2d-xでgetWritablePath以外のファイルパスを取得する

前回シェア機能を実装した時に、Androidにおいてシェアする画像の保存先がgetWritablePathだと他のアプリから画像が参照できず、画像のシェアができないといった問題がありました
また、iOSにおいてはデフォルトのgetWritablePathの保存先がDocumentsになっているため、ダウンロードしたファイルをgetWritablePathに保存しているとアプリ申請でリジェクトを食らうといったことがよくあります
なので、保存先のパスを取得する処理を簡単に実装したのでメモがてらここに貼ります

FilePath.h

#ifndef FilePath_h
#define FilePath_h

#include "cocos2d.h"

class FilePath {
public:
    static std::string getDocumentPath(bool isPublic = false);
    static std::string getCachePath(bool isPublic = false);
    
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
    static std::string getExternalFilesPath();
    static std::string getExternalCachePath();
    
#endif
    
};

#endif /* FilePath_h */

各OS共通のヘッダです
AndroidにおいてはgetDocumentPathは正確にはgetFilesPathあたりの名前が正しいのですが、共通化するためiOSに合わせてます

FilePath_Apple.mm

#include "FilePath.h"
#import <UIKit/UIKit.h>

std::string getPath(NSSearchPathDirectory directory) {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(directory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    std::string strRet = [documentsDirectory UTF8String];
    strRet.append("/");
    return strRet;
}

std::string FilePath::getDocumentPath(bool isPublic) {
    return getPath(NSDocumentDirectory);
}

std::string FilePath::getCachePath(bool isPublic) {
    return getPath(NSCachesDirectory);
}

iOS、Mac用の実装です
getWritablePathの実装をコピペしてNSCachesDirectoryを選べるようにしただけです
isPublic引数はAndroidのためのものなので無視しています

FilePath_Android.cpp

#include "FilePath.h"
#include <jni.h>
#include "platform/android/jni/JniHelper.h"
#include "cocos2d.h"

#define  CLASS_NAME "org/cocos2dx/cpp/FilePath"

USING_NS_CC;

std::string getPath(const char* methodName) {
    JniMethodInfo t;
    std::string str;
    if (JniHelper::getStaticMethodInfo(t, CLASS_NAME, methodName, "()Ljava/lang/String;")) {
        jstring jpath  = (jstring)t.env->CallStaticObjectMethod(t.classID, t.methodID);
        
        const char* npath = t.env->GetStringUTFChars(jpath, NULL);
        str = npath;
        str += "/";
        
        t.env->ReleaseStringUTFChars(jpath, npath);
        t.env->DeleteLocalRef(t.classID);
    }
    return str;
}

std::string FilePath::getDocumentPath(bool isPublic) {
    if (isPublic) {
        return getExternalFilesPath();
    }
    return getPath("getFilesPath");
}

std::string FilePath::getCachePath(bool isPublic) {
    if (isPublic) {
        return getExternalCachePath();
    }
    return getPath("getCachePath");
}

std::string FilePath::getExternalFilesPath() {
    return getPath("getExternalFilesPath");
}

std::string FilePath::getExternalCachePath() {
    return getPath("getExternalCachePath");
}

Android用の実装です
isPublicがtrueならExternalの方のファイルパスを返すようにしています

FilePath.java

package org.cocos2dx.cpp;

import android.content.Context;

import org.cocos2dx.lib.Cocos2dxActivity;

import java.io.File;

public class FilePath {

    public static String getFilesPath() {
        Context con = Cocos2dxActivity.getContext();
        return con.getFilesDir().getAbsolutePath();
    }

    public static String getCachePath() {
        Context con = Cocos2dxActivity.getContext();
        return con.getCacheDir().getAbsolutePath();
    }

    public static String getExternalFilesPath() {
        Context con = Cocos2dxActivity.getContext();
        File file = con.getExternalFilesDir(null);
        if (file != null) {
            return file.getAbsolutePath();
        }
        return "";
    }

    public static String getExternalCachePath() {
        Context con = Cocos2dxActivity.getContext();
        File file = con.getExternalCacheDir();
        if (file != null) {
            return file.getAbsolutePath();
        }
        return "";
    }
}

AndroidのJavaの実装です
Externalのディレクトリがnullだと空白を返しているので注意
ここら辺適当な実装なので気になる方は各自で修正してください
また、Externalのディレクトリに書き込み・読み込みをする場合、以下の権限が必要になるのでAndroidManifest.xmlに以下を追加してください

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

おまけのFilePath.cpp

#include "FilePath.h"
#if CC_TARGET_PLATFORM != CC_PLATFORM_IOS && CC_TARGET_PLATFORM != CC_PLATFORM_MAC && CC_TARGET_PLATFORM != CC_PLATFORM_ANDROID


std::string FilePath::getDocumentPath(bool isPublic) {
    return cocos2d::FileUtils::getInstance()->getWritablePath();
}

std::string FilePath::getCachePath(bool isPublic) {
    return cocos2d::FileUtils::getInstance()->getWritablePath();
}

#endif

iOS、Mac、Android以外の場合の実装です
ビルドを通すためだけのものなので面倒なのでgetWritablePath返しちゃってます

以下この実装を使ったサンプル

        cocos2d::utils::captureScreen([](bool success, std::string filePath) {
            if (success) {
                //前回の記事で実装したシェアのメソッド
                Share::lineSendImage(filePath);
            }
        }, FilePath::getCachePath(true) + "capture.png");

こんな感じでやれば画面のスクリーンショット画像をキャッシュディレクトリに保存してLINEでシェアなんかできたりすると思います

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です