app_mobile_and.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. //go:build !ci && android
  2. // +build !ci,android
  3. #include <android/log.h>
  4. #include <jni.h>
  5. #include <stdbool.h>
  6. #include <stdlib.h>
  7. #define LOG_FATAL(...) __android_log_print(ANDROID_LOG_FATAL, "Fyne", __VA_ARGS__)
  8. static jclass find_class(JNIEnv *env, const char *class_name) {
  9. jclass clazz = (*env)->FindClass(env, class_name);
  10. if (clazz == NULL) {
  11. (*env)->ExceptionClear(env);
  12. LOG_FATAL("cannot find %s", class_name);
  13. return NULL;
  14. }
  15. return clazz;
  16. }
  17. static jmethodID find_method(JNIEnv *env, jclass clazz, const char *name, const char *sig) {
  18. jmethodID m = (*env)->GetMethodID(env, clazz, name, sig);
  19. if (m == 0) {
  20. (*env)->ExceptionClear(env);
  21. LOG_FATAL("cannot find method %s %s", name, sig);
  22. return 0;
  23. }
  24. return m;
  25. }
  26. static jmethodID find_static_method(JNIEnv *env, jclass clazz, const char *name, const char *sig) {
  27. jmethodID m = (*env)->GetStaticMethodID(env, clazz, name, sig);
  28. if (m == 0) {
  29. (*env)->ExceptionClear(env);
  30. LOG_FATAL("cannot find method %s %s", name, sig);
  31. return 0;
  32. }
  33. return m;
  34. }
  35. jobject getSystemService(uintptr_t jni_env, uintptr_t ctx, char *service) {
  36. JNIEnv *env = (JNIEnv*)jni_env;
  37. jstring serviceStr = (*env)->NewStringUTF(env, service);
  38. jclass ctxClass = (*env)->GetObjectClass(env, ctx);
  39. jmethodID getSystemService = find_method(env, ctxClass, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
  40. return (jobject)(*env)->CallObjectMethod(env, ctx, getSystemService, serviceStr);
  41. }
  42. int nextId = 1;
  43. bool isOreoOrLater(JNIEnv *env) {
  44. jclass versionClass = find_class(env, "android/os/Build$VERSION" );
  45. jfieldID sdkIntFieldID = (*env)->GetStaticFieldID(env, versionClass, "SDK_INT", "I" );
  46. int sdkVersion = (*env)->GetStaticIntField(env, versionClass, sdkIntFieldID );
  47. return sdkVersion >= 26; // O = Oreo, will not be defined for older builds
  48. }
  49. jobject parseURL(uintptr_t jni_env, uintptr_t ctx, char* uriCstr) {
  50. JNIEnv *env = (JNIEnv*)jni_env;
  51. jstring uriStr = (*env)->NewStringUTF(env, uriCstr);
  52. jclass uriClass = find_class(env, "android/net/Uri");
  53. jmethodID parse = find_static_method(env, uriClass, "parse", "(Ljava/lang/String;)Landroid/net/Uri;");
  54. return (jobject)(*env)->CallStaticObjectMethod(env, uriClass, parse, uriStr);
  55. }
  56. void openURL(uintptr_t java_vm, uintptr_t jni_env, uintptr_t ctx, char *url) {
  57. JNIEnv *env = (JNIEnv*)jni_env;
  58. jobject uri = parseURL(jni_env, ctx, url);
  59. jclass intentClass = find_class(env, "android/content/Intent");
  60. jfieldID viewFieldID = (*env)->GetStaticFieldID(env, intentClass, "ACTION_VIEW", "Ljava/lang/String;" );
  61. jstring view = (*env)->GetStaticObjectField(env, intentClass, viewFieldID);
  62. jmethodID constructor = find_method(env, intentClass, "<init>", "(Ljava/lang/String;Landroid/net/Uri;)V");
  63. jobject intent = (*env)->NewObject(env, intentClass, constructor, view, uri);
  64. jclass contextClass = find_class(env, "android/content/Context");
  65. jmethodID start = find_method(env, contextClass, "startActivity", "(Landroid/content/Intent;)V");
  66. (*env)->CallVoidMethod(env, ctx, start, intent);
  67. }
  68. void sendNotification(uintptr_t java_vm, uintptr_t jni_env, uintptr_t ctx, char *title, char *body) {
  69. JNIEnv *env = (JNIEnv*)jni_env;
  70. jstring titleStr = (*env)->NewStringUTF(env, title);
  71. jstring bodyStr = (*env)->NewStringUTF(env, body);
  72. jclass cls = find_class(env, "android/app/Notification$Builder");
  73. jmethodID constructor = find_method(env, cls, "<init>", "(Landroid/content/Context;)V");
  74. jobject builder = (*env)->NewObject(env, cls, constructor, ctx);
  75. jclass mgrCls = find_class(env, "android/app/NotificationManager");
  76. jobject mgr = getSystemService(env, ctx, "notification");
  77. if (isOreoOrLater(env)) {
  78. jstring channelId = (*env)->NewStringUTF(env, "fyne-notif");
  79. jstring name = (*env)->NewStringUTF(env, "Fyne Notification");
  80. int importance = 4; // IMPORTANCE_HIGH
  81. jclass chanCls = find_class(env, "android/app/NotificationChannel");
  82. jmethodID constructor = find_method(env, chanCls, "<init>", "(Ljava/lang/String;Ljava/lang/CharSequence;I)V");
  83. jobject channel = (*env)->NewObject(env, chanCls, constructor, channelId, name, importance);
  84. jmethodID createChannel = find_method(env, mgrCls, "createNotificationChannel", "(Landroid/app/NotificationChannel;)V");
  85. (*env)->CallVoidMethod(env, mgr, createChannel, channel);
  86. jmethodID setChannelId = find_method(env, cls, "setChannelId", "(Ljava/lang/String;)Landroid/app/Notification$Builder;");
  87. (*env)->CallObjectMethod(env, builder, setChannelId, channelId);
  88. }
  89. jmethodID setContentTitle = find_method(env, cls, "setContentTitle", "(Ljava/lang/CharSequence;)Landroid/app/Notification$Builder;");
  90. (*env)->CallObjectMethod(env, builder, setContentTitle, titleStr);
  91. jmethodID setContentText = find_method(env, cls, "setContentText", "(Ljava/lang/CharSequence;)Landroid/app/Notification$Builder;");
  92. (*env)->CallObjectMethod(env, builder, setContentText, bodyStr);
  93. int iconID = 17629184; // constant of "unknown app icon"
  94. jmethodID setSmallIcon = find_method(env, cls, "setSmallIcon", "(I)Landroid/app/Notification$Builder;");
  95. (*env)->CallObjectMethod(env, builder, setSmallIcon, iconID);
  96. jmethodID build = find_method(env, cls, "build", "()Landroid/app/Notification;");
  97. jobject notif = (*env)->CallObjectMethod(env, builder, build);
  98. jmethodID notify = find_method(env, mgrCls, "notify", "(ILandroid/app/Notification;)V");
  99. (*env)->CallVoidMethod(env, mgr, notify, nextId, notif);
  100. nextId++;
  101. }