Android cleanup & some finalization
This commit is contained in:
@@ -130,7 +130,7 @@ class InitState extends FlxState
|
||||
#end
|
||||
|
||||
#if mobile
|
||||
// Setup In-App reviews
|
||||
// Setup Mobile FNFC launcher.
|
||||
funkin.mobile.util.FNFCUtil.init();
|
||||
#end
|
||||
|
||||
@@ -403,7 +403,23 @@ class InitState extends FlxState
|
||||
else
|
||||
{
|
||||
// FlxG.sound.cache(Paths.music('freakyMenu/freakyMenu'));
|
||||
#if mobile
|
||||
final fnfcFile = funkin.mobile.util.FNFCUtil.queryFNFC();
|
||||
if (fnfcFile != null)
|
||||
{
|
||||
trace('launching FNFC from $fnfcFile');
|
||||
FlxG.switchState(() -> new ChartPlaytestState(
|
||||
{
|
||||
fnfcFilePath: fnfcFile,
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
FlxG.switchState(() -> new TitleState());
|
||||
}
|
||||
#else
|
||||
FlxG.switchState(() -> new TitleState());
|
||||
#end
|
||||
}
|
||||
#else
|
||||
else
|
||||
|
||||
+36
-42
@@ -7,8 +7,7 @@ import flixel.util.FlxSignal;
|
||||
/**
|
||||
* A Utility class to handle Android API level callbacks and events.
|
||||
*/
|
||||
@:unreflective
|
||||
class CallbackUtil
|
||||
class CallbackUtil #if (lime >= "8.0.0") implements JNISafety #end
|
||||
{
|
||||
/**
|
||||
* The result code for `DATA_FOLDER_CLOSED` activity.
|
||||
@@ -35,7 +34,7 @@ class CallbackUtil
|
||||
*
|
||||
* First argument is the FNFC file path.
|
||||
*/
|
||||
public static var onOpenFNFC:FlxTypedSignal<String->Void> = new FlxTypedSignal<String->Void>();
|
||||
public static var onFNCOpen:FlxTypedSignal<String->Void> = new FlxTypedSignal<String->Void>();
|
||||
|
||||
/**
|
||||
* Initializes the callback utility.
|
||||
@@ -46,46 +45,41 @@ class CallbackUtil
|
||||
|
||||
if (initCallBackJNI != null)
|
||||
{
|
||||
initCallBackJNI(new CallbackHandler());
|
||||
initCallBackJNI(new CallbackUtil());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an Array that contains every static field from this class
|
||||
* @return Array<Dynamic>
|
||||
*/
|
||||
private static function listStaticFields():Array<Dynamic>
|
||||
{
|
||||
return Type.getClassFields(CallbackUtil);
|
||||
}
|
||||
|
||||
@:noCompletion
|
||||
private function new() {}
|
||||
|
||||
@:noCompletion
|
||||
@:keep
|
||||
#if (lime >= "8.0.0")
|
||||
@:runOnMainThread
|
||||
#end
|
||||
private function dispatchCallback(callbackName:String, arguments:Array<Dynamic>)
|
||||
{
|
||||
// TODO: Figure out a way to check if it's a FlxSignal? Don't know if it's possible due to how FlxTypedSignal works
|
||||
if (listStaticFields().contains(callbackName))
|
||||
{
|
||||
// trace('[CALLBACK] Calling ${callbackName} with args ${arguments == null ? "[]" : '[${arguments.join(',')}]'}');
|
||||
final field = Reflect.field(CallbackUtil, callbackName);
|
||||
final method = Reflect.field(field, "dispatch");
|
||||
Reflect.callMethod(field, method, arguments);
|
||||
}
|
||||
else
|
||||
{
|
||||
trace('[CALLBACK] Callback "${callbackName}" not found.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal class to handle native callback events.
|
||||
*/
|
||||
class CallbackHandler #if (lime >= "8.0.0") implements JNISafety #end
|
||||
{
|
||||
@:allow(funkin.external.android.CallbackUtil)
|
||||
function new():Void {}
|
||||
|
||||
/**
|
||||
* Handles the activity result callback from native code.
|
||||
*
|
||||
* @param requestCode The request code of the acitivty.
|
||||
* @param resultCode The result code of the acitivty.
|
||||
*/
|
||||
@:keep
|
||||
#if (lime >= "8.0.0")
|
||||
@:runOnMainThread
|
||||
#end
|
||||
public function onActivityResult(requestCode:Int, resultCode:Int):Void
|
||||
{
|
||||
if (CallbackUtil.onActivityResult != null) CallbackUtil.onActivityResult.dispatch(requestCode, resultCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the onOpenFNFC callback from native code.
|
||||
*
|
||||
* @param file Path to the FNFC file that was opened.
|
||||
*/
|
||||
@:keep
|
||||
#if (lime >= "8.0.0")
|
||||
@:runOnMainThread
|
||||
#end
|
||||
public function onOpenFNFC(file:String):Void
|
||||
{
|
||||
if (CallbackUtil.onOpenFNFC != null) CallbackUtil.onOpenFNFC.dispatch(file);
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
@@ -4,7 +4,6 @@ package funkin.external.android;
|
||||
/**
|
||||
* A Utility class to manage the Application's Data folder on Android.
|
||||
*/
|
||||
@:unreflective
|
||||
class DataFolderUtil
|
||||
{
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,6 @@ import lime.system.JNI;
|
||||
/**
|
||||
* A Utility class to get Android screen related informations.
|
||||
*/
|
||||
@:unreflective
|
||||
class ScreenUtil
|
||||
{
|
||||
/**
|
||||
|
||||
@@ -25,23 +25,80 @@ public class CallbackUtil extends Extension
|
||||
CallbackUtil.haxeObject = haxeObject;
|
||||
}
|
||||
|
||||
public static void callMethod(String methodName, Object[] args)
|
||||
public static void callMethod(String methodName)
|
||||
{
|
||||
if (haxeObject != null)
|
||||
haxeObject.call(methodName, args);
|
||||
{
|
||||
Object[] args = new Object[2];
|
||||
args[0] = methodName;
|
||||
args[1] = new Object[0];
|
||||
haxeObject.call("dispatchCallback", args);
|
||||
}
|
||||
}
|
||||
|
||||
public static void callMethodVoid(String methodName)
|
||||
public static void callMethod(String methodName, Object arg1)
|
||||
{
|
||||
if (haxeObject != null)
|
||||
haxeObject.call0(methodName);
|
||||
{
|
||||
Object[] _args = {arg1};
|
||||
Object[] args = new Object[2];
|
||||
args[0] = methodName;
|
||||
args[1] = _args;
|
||||
haxeObject.call("dispatchCallback", args);
|
||||
}
|
||||
}
|
||||
|
||||
public static void callMethod(String methodName, Object arg1, Object arg2)
|
||||
{
|
||||
if (haxeObject != null)
|
||||
{
|
||||
Object[] _args = {arg1, arg2};
|
||||
Object[] args = new Object[2];
|
||||
args[0] = methodName;
|
||||
args[1] = _args;
|
||||
haxeObject.call("dispatchCallback", args);
|
||||
}
|
||||
}
|
||||
|
||||
public static void callMethod(String methodName, Object arg1, Object arg2, Object arg3)
|
||||
{
|
||||
if (haxeObject != null)
|
||||
{
|
||||
Object[] _args = {arg1, arg2, arg3};
|
||||
Object[] args = new Object[2];
|
||||
args[0] = methodName;
|
||||
args[1] = _args;
|
||||
haxeObject.call("dispatchCallback", args);
|
||||
}
|
||||
}
|
||||
|
||||
public static void callMethod(String methodName, Object arg1, Object arg2, Object arg3, Object arg4)
|
||||
{
|
||||
if (haxeObject != null)
|
||||
{
|
||||
Object[] _args = {arg1, arg2, arg3, arg4};
|
||||
Object[] args = new Object[2];
|
||||
args[0] = methodName;
|
||||
args[1] = _args;
|
||||
haxeObject.call("dispatchCallback", args);
|
||||
}
|
||||
}
|
||||
|
||||
public static void callMethod(String methodName, Object[] args)
|
||||
{
|
||||
if (haxeObject != null)
|
||||
{
|
||||
Object[] _args = new Object[2];
|
||||
args[0] = methodName;
|
||||
args[1] = args;
|
||||
haxeObject.call("dispatchCallback", _args);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActivityResult(int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
if (haxeObject != null)
|
||||
haxeObject.call2("onActivityResult", requestCode, resultCode);
|
||||
callMethod("onActivityResult", requestCode, resultCode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2,16 +2,18 @@ package funkin.extensions;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import funkin.extensions.CallbackUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
|
||||
import org.haxe.extension.Extension;
|
||||
|
||||
@@ -19,7 +21,9 @@ import org.haxe.lime.HaxeObject;
|
||||
|
||||
public class FNFCExtension extends Extension
|
||||
{
|
||||
public static String launchedFile = null;
|
||||
public static final String LOG_TAG = "FNFCExtension";
|
||||
|
||||
public static String lastFNFC = null;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
@@ -40,41 +44,86 @@ public class FNFCExtension extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public static String queryLaunchedFNFC()
|
||||
{
|
||||
return launchedFile;
|
||||
}
|
||||
|
||||
|
||||
private static void handleIntent(Intent intent, boolean doCallback)
|
||||
{
|
||||
if (Intent.ACTION_VIEW.equals(intent.getAction())) {
|
||||
if (Intent.ACTION_VIEW.equals(intent.getAction()))
|
||||
{
|
||||
Uri uri = intent.getData();
|
||||
if (uri != null) {
|
||||
File output = new File(mainContext.getCacheDir(), new File("fnfc", uri.getPath()).getName());
|
||||
if (uri != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
lastFNFC = copyFNFCToCache(uri);
|
||||
|
||||
try {
|
||||
InputStream in = mainContext.getContentResolver().openInputStream(uri);
|
||||
OutputStream out = new FileOutputStream(output);
|
||||
byte[] buffer = new byte[8192];
|
||||
int len;
|
||||
while ((len = in.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, len);
|
||||
if (doCallback)
|
||||
{
|
||||
CallbackUtil.callMethod("onFNCOpen", lastFNFC);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.e("Exception", e.getMessage());
|
||||
}
|
||||
|
||||
launchedFile = output.getAbsolutePath();
|
||||
|
||||
if (doCallback)
|
||||
catch (IOException e)
|
||||
{
|
||||
Object[] args = new Object[1];
|
||||
args[0] = launchedFile;
|
||||
CallbackUtil.callMethod("onOpenFNFC", args);
|
||||
Log.e(LOG_TAG, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String copyFNFCToCache(Uri uri) throws IOException
|
||||
{
|
||||
if (uri != null)
|
||||
{
|
||||
String fileName = new File(uri.getPath()).getName();
|
||||
|
||||
// Clean some Uri leftovers
|
||||
if (fileName.contains(":"))
|
||||
fileName = fileName.split(":")[1];
|
||||
|
||||
File cacheFNFC = new File(mainContext.getCacheDir(), "fnfc");
|
||||
File output = new File(cacheFNFC, fileName);
|
||||
|
||||
if (!cacheFNFC.exists())
|
||||
cacheFNFC.mkdir();
|
||||
|
||||
if (output.exists())
|
||||
output.delete();
|
||||
|
||||
ParcelFileDescriptor parcelFileDescriptor = null;
|
||||
FileInputStream fileInputStream = null;
|
||||
OutputStream out = null;
|
||||
|
||||
try
|
||||
{
|
||||
parcelFileDescriptor = mainContext.getContentResolver().openFileDescriptor(uri, "r");
|
||||
fileInputStream = new FileInputStream(parcelFileDescriptor.getFileDescriptor());
|
||||
|
||||
byte[] fileBytes = new byte[(int) parcelFileDescriptor.getStatSize()];
|
||||
fileInputStream.read(fileBytes);
|
||||
|
||||
out = new FileOutputStream(output);
|
||||
out.write(fileBytes);
|
||||
|
||||
if (output.exists())
|
||||
output.deleteOnExit(); // makes the file get deleted when the app closes ig?
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Log.e(LOG_TAG, e.getMessage());
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (fileInputStream != null)
|
||||
fileInputStream.close();
|
||||
|
||||
if (parcelFileDescriptor != null)
|
||||
parcelFileDescriptor.close();
|
||||
|
||||
if (out != null)
|
||||
out.close();
|
||||
}
|
||||
|
||||
return output.getAbsolutePath();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,11 @@ package funkin.mobile.util;
|
||||
#if ios
|
||||
import funkin.external.apple.FNFCUtil as NativeFNFCUtil;
|
||||
#end
|
||||
#if android
|
||||
import funkin.external.android.JNIUtil;
|
||||
import funkin.external.android.CallbackUtil;
|
||||
#end
|
||||
import lime.system.System;
|
||||
import flixel.util.FlxSignal;
|
||||
|
||||
/**
|
||||
@@ -18,10 +23,30 @@ class FNFCUtil
|
||||
|
||||
#if ios
|
||||
FlxG.stage.window.onDropFile.add(function(_) {
|
||||
final url = lime.system.System.getHint("IOS_UIApplicationLaunchOptionsURLKey");
|
||||
onFNCOpen.dispatch(getFNFCFromURL(url));
|
||||
final url = queryFNFC();
|
||||
if (url != null) onFNCOpen.dispatch(getFNFCFromURL(url));
|
||||
});
|
||||
#elseif android
|
||||
CallbackUtil.onFNCOpen.add(onFNCOpen.dispatch);
|
||||
#end
|
||||
|
||||
final fnfcFile:String = queryFNFC();
|
||||
|
||||
if (fnfcFile != null)
|
||||
{
|
||||
trace('Got FNFC File from $fnfcFile!');
|
||||
}
|
||||
}
|
||||
|
||||
public static function queryFNFC():Null<String>
|
||||
{
|
||||
#if ios
|
||||
return System.getHint("IOS_UIApplicationLaunchOptionsURLKey");
|
||||
#elseif android
|
||||
final staticField = JNIUtil.createStaticField('funkin/extensions/FNFCExtension', 'lastFNFC', 'Ljava/lang/String;');
|
||||
if (staticField != null) return staticField.get();
|
||||
#end
|
||||
return null;
|
||||
}
|
||||
|
||||
#if ios
|
||||
@@ -30,7 +55,8 @@ class FNFCUtil
|
||||
* @param url A iOS `file://` URL.
|
||||
* @return The new path that the file the URL points at inside of the cache directory.
|
||||
*/
|
||||
public static function getFNFCFromURL(url:String):String
|
||||
@:noCompletion
|
||||
private static function getFNFCFromURL(url:String):String
|
||||
{
|
||||
var cURL:cpp.ConstCharStar = cast url;
|
||||
|
||||
|
||||
@@ -445,6 +445,11 @@ class PolymodHandler
|
||||
var className:String = Type.getClassName(cls);
|
||||
Polymod.blacklistImport(className);
|
||||
}
|
||||
|
||||
// External classes for android that bridge to private JNI methods & callbacks
|
||||
Polymod.blacklistImport('funkin.external.android.CallbackUtil');
|
||||
Polymod.blacklistImport('funkin.external.android.DataFolderUtil');
|
||||
Polymod.blacklistImport('funkin.external.android.JNIUtil');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -91,9 +91,9 @@ class ReloadAssetsDebugPlugin extends FlxBasic
|
||||
|
||||
#if android
|
||||
@:noCompletion
|
||||
function onActivityResult(resultCode:Int, requestCode:Int):Void
|
||||
function onActivityResult(requestCode:Int, resultCode:Int):Void
|
||||
{
|
||||
if (resultCode == CallbackUtil.DATA_FOLDER_CLOSED)
|
||||
if (requestCode == CallbackUtil.DATA_FOLDER_CLOSED)
|
||||
{
|
||||
reload();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user