mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
Added support for data directory on Android.
This makes GNUstep use the path returned by Context.getFilesDir() as the basis for storing data (e.g. NSUserDefaults) and when querying system directory paths (NSLibraryDirectory, NSApplicationSupportDirectory, etc.). Requires calling a new GSInitializeProcessAndroid() initialization function.
This commit is contained in:
parent
ae95e859d6
commit
d23c5013bf
4 changed files with 113 additions and 31 deletions
11
ChangeLog
11
ChangeLog
|
@ -1,3 +1,14 @@
|
|||
2019-09-25 Frederik Seiffert <frederik@algoriddim.com>
|
||||
|
||||
* Headers/Foundation/NSProcessInfo.h:
|
||||
* Source/NSPathUtilities.m:
|
||||
* Source/NSProcessInfo.m:
|
||||
Added support for data directory on Android. This makes GNUstep use
|
||||
the path returned by Context.getFilesDir() as the basis for storing
|
||||
data (e.g. NSUserDefaults) and when querying system directory paths
|
||||
(NSLibraryDirectory, NSApplicationSupportDirectory, etc.). Requires
|
||||
calling a new GSInitializeProcessAndroid() initialization function.
|
||||
|
||||
2019-09-25 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Source/NSArray.m: [-removeObjectsInArray:] add checks to prevent
|
||||
|
|
|
@ -30,6 +30,10 @@
|
|||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <jni.h>
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -265,6 +269,12 @@ DEFINE_BLOCK_TYPE(GSPerformExpiringActivityBlock, void, BOOL);
|
|||
+ (void) initializeWithArguments: (char**)argv
|
||||
count: (int)argc
|
||||
environment: (char**)env;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
- (jobject) androidContext;
|
||||
- (NSString *) androidFilesDir;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
|
@ -278,6 +288,16 @@ DEFINE_BLOCK_TYPE(GSPerformExpiringActivityBlock, void, BOOL);
|
|||
*/
|
||||
GS_EXPORT void GSInitializeProcess(int argc, char **argv, char **envp);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
/**
|
||||
* Android process initialization function.
|
||||
* This should be called on Android to initialize GNUstep with the JNI
|
||||
* environment and application context, which is used to set up support
|
||||
* for the Android data directory and asset loading via NSBundle.
|
||||
*/
|
||||
GS_EXPORT void GSInitializeProcessAndroid(JNIEnv *env, jobject context);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Function for rapid testing to see if a debug level is set.<br />
|
||||
* This is used by the debugging macros.<br />
|
||||
|
|
|
@ -1740,7 +1740,9 @@ NSHomeDirectoryForUser(NSString *loginName)
|
|||
{
|
||||
NSString *s = nil;
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#ifdef __ANDROID__
|
||||
s = [[NSProcessInfo processInfo] androidFilesDir];
|
||||
#elif !defined(_WIN32)
|
||||
#if defined(HAVE_GETPWNAM_R)
|
||||
struct passwd pw;
|
||||
struct passwd *p;
|
||||
|
|
|
@ -230,6 +230,12 @@ static NSString *_operatingSystemVersion = nil;
|
|||
static BOOL fallbackInitialisation = NO;
|
||||
|
||||
static NSMutableSet *mySet = nil;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
static jobject _androidContext = NULL;
|
||||
static NSString *_androidFilesDir = nil;
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
*** Implementing the gnustep_base_user_main function
|
||||
*************************************************************************/
|
||||
|
@ -943,36 +949,6 @@ extern char **__libc_argv;
|
|||
}
|
||||
}
|
||||
|
||||
#elif defined(__ANDROID__)
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (nil == procLock) procLock = [NSRecursiveLock new];
|
||||
if (self == [NSProcessInfo class]
|
||||
&& !_gnu_processName && !_gnu_arguments && !_gnu_environment)
|
||||
{
|
||||
FILE *f = fopen("/proc/self/cmdline", "r");
|
||||
|
||||
if (f)
|
||||
{
|
||||
char identifier[BUFSIZ];
|
||||
fgets(identifier, sizeof(identifier), f);
|
||||
fclose(f);
|
||||
|
||||
// construct fake executable path
|
||||
char *arg0;
|
||||
asprintf(&arg0, "/data/data/%s/exe", identifier);
|
||||
|
||||
char *argv[] = { arg0 };
|
||||
_gnu_process_args(sizeof(argv)/sizeof(char *), argv, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Failed to read cmdline\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
+ (void) initialize
|
||||
{
|
||||
|
@ -1589,6 +1565,66 @@ GSInitializeProcess(int argc, char **argv, char **envp)
|
|||
[procLock unlock];
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
void
|
||||
GSInitializeProcessAndroid(JNIEnv *env, jobject context)
|
||||
{
|
||||
[NSProcessInfo class];
|
||||
|
||||
// create global reference to to prevent garbage collection
|
||||
_androidContext = (*env)->NewGlobalRef(env, context);
|
||||
|
||||
// get package code path (path to APK)
|
||||
jclass cls = (*env)->GetObjectClass(env, context);
|
||||
jmethodID packageCodePathMethod = (*env)->GetMethodID(env, cls, "getPackageCodePath", "()Ljava/lang/String;");
|
||||
jstring packageCodePathJava = (*env)->CallObjectMethod(env, context, packageCodePathMethod);
|
||||
const char *packageCodePath = (*env)->GetStringUTFChars(env, packageCodePathJava, NULL);
|
||||
|
||||
// get package name
|
||||
jmethodID packageNameMethod = (*env)->GetMethodID(env, cls, "getPackageName", "()Ljava/lang/String;");
|
||||
jstring packageNameJava = (*env)->CallObjectMethod(env, context, packageNameMethod);
|
||||
const char *packageName = (*env)->GetStringUTFChars(env, packageNameJava, NULL);
|
||||
|
||||
// create fake executable path consisting of package code path (without .apk)
|
||||
// and package name as executable
|
||||
char *lastSlash = strrchr(packageCodePath, '/');
|
||||
if (lastSlash == NULL)
|
||||
{
|
||||
lastSlash = (char *)packageCodePath + strlen(packageCodePath);
|
||||
}
|
||||
char *arg0;
|
||||
asprintf(&arg0, "%.*s/%s", (int)(lastSlash - packageCodePath), packageCodePath, packageName);
|
||||
|
||||
(*env)->ReleaseStringUTFChars(env, packageCodePathJava, packageCodePath);
|
||||
(*env)->ReleaseStringUTFChars(env, packageNameJava, packageName);
|
||||
|
||||
// initialize process
|
||||
[procLock lock];
|
||||
fallbackInitialisation = YES;
|
||||
char *argv[] = { arg0 };
|
||||
_gnu_process_args(sizeof(argv)/sizeof(char *), argv, NULL);
|
||||
[procLock unlock];
|
||||
|
||||
free(arg0);
|
||||
|
||||
// get Android files dir
|
||||
jmethodID filesDirMethod = (*env)->GetMethodID(env, cls, "getFilesDir", "()Ljava/io/File;");
|
||||
jobject filesDirObj = (*env)->CallObjectMethod(env, context, filesDirMethod);
|
||||
jclass filesDirCls = (*env)->GetObjectClass(env, filesDirObj);
|
||||
jmethodID getStoragePath = (*env)->GetMethodID(env, filesDirCls, "getAbsolutePath", "()Ljava/lang/String;");
|
||||
jstring filesDirJava = (*env)->CallObjectMethod(env, filesDirObj, getStoragePath);
|
||||
const jchar *unichars = (*env)->GetStringChars(env, filesDirJava, NULL);
|
||||
jsize length = (*env)->GetStringLength(env, filesDirJava);
|
||||
_androidFilesDir = [NSString stringWithCharacters:unichars length:length];
|
||||
(*env)->ReleaseStringChars(env, filesDirJava, unichars);
|
||||
|
||||
// get asset manager and initialize NSBundle
|
||||
jmethodID assetManagerMethod = (*env)->GetMethodID(env, cls, "getAssets", "()Landroid/content/res/AssetManager;");
|
||||
jstring assetManagerJava = (*env)->CallObjectMethod(env, context, assetManagerMethod);
|
||||
[NSBundle setJavaAssetManager:assetManagerJava withJNIEnv:env];
|
||||
}
|
||||
#endif
|
||||
|
||||
@implementation NSProcessInfo (GNUstep)
|
||||
|
||||
+ (void) initializeWithArguments: (char**)argv
|
||||
|
@ -1620,6 +1656,19 @@ GSInitializeProcess(int argc, char **argv, char **envp)
|
|||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
- (jobject) androidContext
|
||||
{
|
||||
return _androidContext;
|
||||
}
|
||||
|
||||
- (NSString *) androidFilesDir
|
||||
{
|
||||
return _androidFilesDir;
|
||||
}
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
BOOL
|
||||
|
|
Loading…
Reference in a new issue