JavaScript
Android
cocos2d-x
TwitterKit

cocos2dx(js)のAndroidでRenderTexture.filetosaveで生成した画像がTwitterにpostできなかった問題の対処

環境

cocos2d-x 3.16
Fabric
TwitterKit 2.3.0

問題

coffee
callback = (texture, savedPath)->
  cc.log savedPath

size = cc.director.getWinSize()
tex = new cc.RenderTexture(size.width, size.height)
# ...中略...
tex.saveToFile('screenshot.png', cc.IMAGE_FORMAT_PNG, undefined, callback)

こんな感じでセーブし、callbacksavedPathを見ると

/data/data/**APPLICATION_ID**/files/screenshot.png

となっていた。ちなみに上書きされる模様。(**APPLICATION_ID**はManifestに書くやつ)
これをtwitterkitで投稿するために、ネイティブのメソッドを叩く。

coffee
path = savedPath
tweet = 'ついーと内容'
url = 'https://revinx.net/'

jsb.reflection.callStaticMethod(
  "org/cocos2dx/javascript/AppActivity"
  "tweet"
  "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"
  path
  tweet
  url
)

ネイティブ側。

java
public class AppActivity extends Cocos2dxActivity {
    // ...
    // 中略
    // ...
    public static void tweet(final String path, final String tweetText, final String url) {
        File f = new File(path);
        Uri u = Uri.fromFile(f);

        TweetComposer.Builder builder;
        try {
            builder = new TweetComposer.Builder(activity)
                    .text(tweetText)
                    .image(u)
                    .url(new URL(url));
            builder.show();
        } catch (MalformedURLException e) {
        }
    }
}

でいいはずなんだが、画像が添付されてない。
たぶんTweetComposerで開くやつがこのアプリではないので、このアプリで保存したpathにあるファイルを読めないのだと思われる。
エラーメッセージに↓のようなのが出まくる。

errorlog
Failed to mkdirat(/storage/sdcard1/Android): Read-only file system

また、↓のようなのを用意してパブリックな場所にsavetofileしようとしてもダメだった。

java
public class Utils {
    public static String getPublicPath() {
        File pathExternalPublicDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
        String dir = pathExternalPublicDir.getAbsolutePath();
        return dir;
    }
}
coffee
dir = jsb.reflection.callStaticMethod("**PACKAGE_ID**/Utils", "getPublicPath", "()Ljava/lang/String;")
tex.saveToFile(dir+'/screenshot.png', cc.IMAGE_FORMAT_PNG, undefined, callback)

**PACKAGE_ID**はなんかJavaの先頭あたりでpackageで定義するやつ)
フルパスだめなのかな。

対処

ネイティブ側でツイートする前にアプリ領域からパブリック領域にコピーしたらできた。

coffee
path = savedPath
filename = 'public_screenshot.png'
tweet = 'ついーと内容'
url = 'https://revinx.net/'

jsb.reflection.callStaticMethod(
  "org/cocos2dx/javascript/AppActivity"
  "tweet"
  "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"
  path
  filename
  tweet
  url
)

ネイティブ側。

java
public class AppActivity extends Cocos2dxActivity {
    // ...
    // 中略
    // ...
    public static void tweet(final String path, final String filename, final String tweetText, final String url) {
        String to = Utils.getDownloadsPath()+"/"+filename;
        Utils.copy(path, to);

        File f = new File(to);
        Uri u = Uri.fromFile(f);

        TweetComposer.Builder builder;
        try {
            builder = new TweetComposer.Builder(activity)
                    .text(tweetText)
                    .image(u)
                    .url(new URL(url));
            builder.show();
        } catch (MalformedURLException e) {
        }
    }
}

public class Utils {
    public static void copy (String source, String to) {
        try {
            FileInputStream fileIn = new FileInputStream(source);
            FileOutputStream fileOut = new FileOutputStream(to);

            byte[] buf = new byte[256];
            int len;

            while ((len = fileIn.read(buf)) != -1) {
                fileOut.write(buf);
            }

            fileOut.flush();

            fileOut.close();
            fileIn.close();
        } catch (IOException e) {
        }
    }
}

これでいけました。
Javaぜんぜん知らないのもあって2日ぐらいハマってしまった。