mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
Merge pull request #73 from triplef/android-paths-support
Added support for data directory on Android.
This commit is contained in:
commit
ecc7444e61
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