* refa: jni

* refa: jni
This commit is contained in:
My-Responsitories
2026-05-30 12:10:35 +00:00
committed by dom
parent f3f871c893
commit 1a7678ee0f
17 changed files with 530 additions and 177 deletions

View File

@@ -0,0 +1,84 @@
package com.example.piliplus;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import androidx.annotation.Keep;
import com.github.dart_lang.jni_flutter.JniFlutterPlugin;
import org.jetbrains.annotations.NotNull;
@Keep
public final class AndroidHelper {
private AndroidHelper() {
}
private static Context getContext() {
return JniFlutterPlugin.getApplicationContext();
}
public static void back() {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getContext().startActivity(intent);
}
public static int sdkInt() {
return Build.VERSION.SDK_INT;
}
public static void openLinkVerifySettings() {
Context context = getContext();
Uri uri = Uri.parse("package:" + context.getPackageName());
try {
Intent intent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
intent = new Intent(Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS, uri);
} else {
intent = new Intent(Intent.ACTION_MAIN, uri);
intent.setClassName(
"com.android.settings",
"com.android.settings.applications.InstalledAppOpenByDefaultActivity"
);
}
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
} catch (Throwable ignored) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, uri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
public static void createShortcut(@NotNull String id, @NotNull String uri, @NotNull String label, @NotNull String icon) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Context context = getContext();
ShortcutManager shortcutManager = context.getSystemService(ShortcutManager.class);
if (shortcutManager != null && shortcutManager.isRequestPinShortcutSupported()) {
Bitmap bitmap = BitmapFactory.decodeFile(icon);
ShortcutInfo shortcut = new ShortcutInfo.Builder(context, id)
.setShortLabel(label)
.setIcon(Icon.createWithAdaptiveBitmap(bitmap))
.setIntent(new Intent(Intent.ACTION_VIEW, Uri.parse(uri)))
.build();
// TODO: WorkerThread
Intent pinIntent = shortcutManager.createShortcutResultIntent(shortcut);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
context, 0, pinIntent, PendingIntent.FLAG_IMMUTABLE
);
shortcutManager.requestPinShortcut(shortcut, pendingIntent.getIntentSender());
}
}
}
}

View File

@@ -1,22 +1,15 @@
package com.example.piliplus
import android.app.PendingIntent
import android.app.SearchManager
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager
import android.content.res.Configuration
import android.graphics.BitmapFactory
import android.graphics.drawable.Icon
import android.os.Build
import android.provider.MediaStore
import android.provider.Settings
import androidx.core.net.toUri
import android.os.Bundle
import android.view.WindowManager.LayoutParams
import com.ryanheise.audioservice.AudioServiceActivity
import io.flutter.SystemChrome
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import io.flutter.SystemChrome
class MainActivity : AudioServiceActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
@@ -25,115 +18,15 @@ class MainActivity : AudioServiceActivity() {
val methodChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "PiliPlus")
methodChannel.setMethodCallHandler { call, result ->
when (call.method) {
"back" -> back()
"linkVerifySettings" -> {
val uri = ("package:" + context.packageName).toUri()
try {
val intent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
Intent(Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS, uri)
} else {
Intent("android.intent.action.MAIN", uri).setClassName(
"com.android.settings",
"com.android.settings.applications.InstalledAppOpenByDefaultActivity"
)
}
context.startActivity(intent)
} catch (_: Throwable) {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, uri)
context.startActivity(intent)
}
}
"music" -> {
val title = call.argument<String>("title")
val intent = Intent(MediaStore.INTENT_ACTION_MEDIA_SEARCH).apply {
putExtra(SearchManager.QUERY, title)
putExtra(MediaStore.EXTRA_MEDIA_TITLE, title)
call.argument<String?>("artist")
?.let { putExtra(MediaStore.EXTRA_MEDIA_ARTIST, it) }
call.argument<String?>("album")
?.let { putExtra(MediaStore.EXTRA_MEDIA_ALBUM, it) }
addCategory(Intent.CATEGORY_DEFAULT)
}
try {
if (packageManager.resolveActivity(
intent,
PackageManager.MATCH_DEFAULT_ONLY
) != null
) {
startActivity(intent)
result.success(true)
return@setMethodCallHandler
}
} catch (_: Throwable) {
}
try {
intent.action = MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH
if (packageManager.resolveActivity(
intent,
PackageManager.MATCH_DEFAULT_ONLY
) != null
) {
startActivity(intent)
result.success(true)
return@setMethodCallHandler
}
} catch (_: Throwable) {
}
result.success(false)
}
"createShortcut" -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
try {
val shortcutManager =
context.getSystemService(ShortcutManager::class.java)
if (shortcutManager.isRequestPinShortcutSupported) {
val id = call.argument<String>("id")!!
val uri = call.argument<String>("uri")!!
val label = call.argument<String>("label")!!
val icon = call.argument<String>("icon")!!
val bitmap = BitmapFactory.decodeFile(icon)
val shortcut =
ShortcutInfo.Builder(context, id)
.setShortLabel(label)
.setIcon(Icon.createWithAdaptiveBitmap(bitmap))
.setIntent(Intent(Intent.ACTION_VIEW, uri.toUri()))
.build()
val pinIntent =
shortcutManager.createShortcutResultIntent(shortcut)
val pendingIntent = PendingIntent.getBroadcast(
context, 0, pinIntent, PendingIntent.FLAG_IMMUTABLE
)
shortcutManager.requestPinShortcut(
shortcut,
pendingIntent.intentSender
)
}
} catch (_: Exception) {
}
}
}
"sdkInt" -> {
result.success(Build.VERSION.SDK_INT)
}
"SystemChrome.setEnabledSystemUIMode" -> {
SystemChrome.onMethodCall(
this,
"SystemChrome.setEnabledSystemUIMode",
call.argument("arguments")
this, "SystemChrome.setEnabledSystemUIMode", call.argument("arguments")
)
}
"SystemChrome.setEnabledSystemUIOverlays" -> {
SystemChrome.onMethodCall(
this,
"SystemChrome.setEnabledSystemUIOverlays",
call.argument("arguments")
this, "SystemChrome.setEnabledSystemUIOverlays", call.argument("arguments")
)
}
@@ -142,12 +35,12 @@ class MainActivity : AudioServiceActivity() {
}
}
private fun back() {
val intent = Intent(Intent.ACTION_MAIN).apply {
addCategory(Intent.CATEGORY_HOME)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
window.attributes.layoutInDisplayCutoutMode =
LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
}
startActivity(intent)
}
override fun onDestroy() {
@@ -156,13 +49,11 @@ class MainActivity : AudioServiceActivity() {
}
override fun onPictureInPictureModeChanged(
isInPictureInPictureMode: Boolean,
newConfig: Configuration?
isInPictureInPictureMode: Boolean, newConfig: Configuration?
) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
MethodChannel(
flutterEngine!!.dartExecutor.binaryMessenger,
"floating"
).invokeMethod("onPipChanged", isInPictureInPictureMode)
MethodChannel(flutterEngine!!.dartExecutor.binaryMessenger, "floating").invokeMethod(
"onPipChanged", isInPictureInPictureMode
)
}
}

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

View File

@@ -18,7 +18,6 @@ import 'package:PiliPlus/services/service_locator.dart';
import 'package:PiliPlus/utils/cache_manager.dart';
import 'package:PiliPlus/utils/calc_window_position.dart';
import 'package:PiliPlus/utils/date_utils.dart';
import 'package:PiliPlus/utils/device_utils.dart';
import 'package:PiliPlus/utils/extension/theme_ext.dart';
import 'package:PiliPlus/utils/json_file_handler.dart';
import 'package:PiliPlus/utils/path_utils.dart';
@@ -84,10 +83,6 @@ Future<void> _initAppPath() async {
appSupportDirPath = (await getApplicationSupportDirectory()).path;
}
Future<void> _initSdkInt() async {
DeviceUtils.sdkInt = await Utils.channel.invokeMethod('sdkInt');
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
MediaKit.ensureInitialized();
@@ -109,7 +104,6 @@ void main() async {
if (PlatformUtils.isMobile) {
await Future.wait([
if (Platform.isAndroid) _initSdkInt(),
if (Pref.horizontalScreen) ?fullMode() else ?portraitUpMode(),
setupServiceLocator(),
]);

View File

@@ -12,6 +12,7 @@ import 'package:PiliPlus/pages/mine/controller.dart';
import 'package:PiliPlus/services/logger.dart';
import 'package:PiliPlus/utils/accounts.dart';
import 'package:PiliPlus/utils/accounts/account.dart';
import 'package:PiliPlus/utils/android/bindings.g.dart';
import 'package:PiliPlus/utils/app_scheme.dart';
import 'package:PiliPlus/utils/cache_manager.dart';
import 'package:PiliPlus/utils/date_utils.dart';
@@ -179,7 +180,7 @@ Commit Hash: ${BuildConfig.commitHash}''',
),
if (Platform.isAndroid)
ListTile(
onTap: () => Utils.channel.invokeMethod('linkVerifySettings'),
onTap: AndroidHelper.openLinkVerifySettings,
leading: const Icon(MdiIcons.linkBoxOutline),
title: const Text('打开受支持的链接'),
trailing: Icon(

View File

@@ -10,6 +10,7 @@ import 'package:PiliPlus/models/common/nav_bar_config.dart';
import 'package:PiliPlus/pages/home/view.dart';
import 'package:PiliPlus/pages/main/controller.dart';
import 'package:PiliPlus/plugin/pl_player/controller.dart';
import 'package:PiliPlus/utils/android/bindings.g.dart';
import 'package:PiliPlus/utils/app_scheme.dart';
import 'package:PiliPlus/utils/extension/context_ext.dart';
import 'package:PiliPlus/utils/extension/size_ext.dart';
@@ -18,7 +19,6 @@ import 'package:PiliPlus/utils/mobile_observer.dart';
import 'package:PiliPlus/utils/platform_utils.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/storage_key.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
@@ -202,9 +202,10 @@ class _MainAppState extends PopScopeState<MainApp>
await trayManager.setContextMenu(trayMenu);
}
@pragma('vm:prefer-inline')
static void _onBack() {
if (Platform.isAndroid) {
Utils.channel.invokeMethod('back');
AndroidHelper.back();
}
}

View File

@@ -33,6 +33,7 @@ import 'package:PiliPlus/pages/member_shop/view.dart';
import 'package:PiliPlus/pages/member_video_web/archive/view.dart';
import 'package:PiliPlus/pages/member_video_web/season_series/view.dart';
import 'package:PiliPlus/pages/webview/view.dart';
import 'package:PiliPlus/utils/android/android_helper.dart';
import 'package:PiliPlus/utils/date_utils.dart';
import 'package:PiliPlus/utils/extension/context_ext.dart';
import 'package:PiliPlus/utils/extension/string_ext.dart';
@@ -704,14 +705,11 @@ class _MemberPageState extends State<MemberPage> {
'${_userController.userAvatar!}@200w_200h.webp'.http2https,
));
SmartDialog.dismiss();
await Utils.channel.invokeMethod(
'createShortcut',
<String, String>{
'id': _userController.mid.toString(),
'uri': 'bilibili://space/${_userController.mid}',
'label': _userController.username!,
'icon': file.path,
},
PiliAndroidHelper.createShortcut(
_userController.mid.toString(),
'bilibili://space/${_userController.mid}',
_userController.username!,
file.path,
);
} catch (e) {
SmartDialog.showToast(e.toString());

View File

@@ -1,4 +1,3 @@
import 'dart:io' show Platform;
import 'dart:math' as math;
import 'package:PiliPlus/common/widgets/badge.dart';
@@ -428,15 +427,10 @@ class _MusicDetailPageState extends CommonDynPageState<MusicDetailPage> {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
onTap: () => _searchMusic(item),
onLongPress: () => Utils.copyText(item.musicTitle!),
behavior: HitTestBehavior.opaque,
child: MarqueeText(
item.musicTitle!,
spacing: 30,
style: textTheme.titleMedium,
),
MarqueeText(
item.musicTitle!,
spacing: 30,
style: textTheme.titleMedium,
),
Wrap(
spacing: 8,
@@ -558,18 +552,4 @@ class _MusicDetailPageState extends CommonDynPageState<MusicDetailPage> {
),
);
}
Future<void> _searchMusic(MusicDetail item) async {
final res =
Platform.isAndroid &&
(await Utils.channel.invokeMethod<bool>('music', {
'title': item.musicTitle,
'artist': item.originArtist ?? item.originArtistList,
'album': item.album,
}) ??
false);
if (!res) {
Utils.copyText(item.musicTitle!);
}
}
}

View File

@@ -0,0 +1,19 @@
import 'package:PiliPlus/utils/android/bindings.g.dart';
import 'package:jni/jni.dart';
abstract final class PiliAndroidHelper {
static void createShortcut(String id, String uri, String label, String path) {
final jId = id.toJString();
final jUri = uri.toJString();
final jLabel = label.toJString();
final jPath = path.toJString();
try {
AndroidHelper.createShortcut(jId, jUri, jLabel, jPath);
} finally {
jId.release();
jUri.release();
jLabel.release();
jPath.release();
}
}
}

View File

@@ -0,0 +1,342 @@
// AUTO GENERATED BY JNIGEN 0.17.0. DO NOT EDIT!
// ignore_for_file: annotate_overrides
// ignore_for_file: argument_type_not_assignable
// ignore_for_file: camel_case_extensions
// ignore_for_file: camel_case_types
// ignore_for_file: constant_identifier_names
// ignore_for_file: comment_references
// ignore_for_file: doc_directive_unknown
// ignore_for_file: file_names
// ignore_for_file: inference_failure_on_untyped_parameter
// ignore_for_file: invalid_internal_annotation
// ignore_for_file: invalid_use_of_internal_member
// ignore_for_file: library_prefixes
// ignore_for_file: lines_longer_than_80_chars
// ignore_for_file: no_leading_underscores_for_library_prefixes
// ignore_for_file: no_leading_underscores_for_local_identifiers
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: only_throw_errors
// ignore_for_file: overridden_fields
// ignore_for_file: prefer_double_quotes
// ignore_for_file: unintended_html_in_doc_comment
// ignore_for_file: unnecessary_cast
// ignore_for_file: unnecessary_non_null_assertion
// ignore_for_file: unnecessary_parenthesis
// ignore_for_file: unused_element
// ignore_for_file: unused_field
// ignore_for_file: unused_import
// ignore_for_file: unused_local_variable
// ignore_for_file: unused_shown_name
// ignore_for_file: use_super_parameters
import 'dart:core' as core$_;
import 'dart:core' show Object, String;
import 'package:jni/_internal.dart' as jni$_;
import 'package:jni/jni.dart' as jni$_;
const _$jniVersionCheck = jni$_.JniVersionCheck(1, 0);
/// from: `java.lang.Runnable`
extension type Runnable._(jni$_.JObject _$this) implements jni$_.JObject {
static final _class = jni$_.JClass.forName(r'java/lang/Runnable');
/// The type which includes information such as the signature of this class.
static const jni$_.JType<Runnable> type = $Runnable$Type$();
/// Maps a specific port to the implemented interface.
static final core$_.Map<core$_.int, $Runnable> _$impls = {};
static jni$_.JObjectPtr _$invoke(
core$_.int port,
jni$_.JObjectPtr descriptor,
jni$_.JObjectPtr args,
) {
return _$invokeMethod(
port,
jni$_.MethodInvocation.fromAddresses(
0,
descriptor.address,
args.address,
),
);
}
static final jni$_.Pointer<
jni$_.NativeFunction<
jni$_.JObjectPtr Function(jni$_.Int64, jni$_.JObjectPtr, jni$_.JObjectPtr)
>
>
_$invokePointer = jni$_.Pointer.fromFunction(_$invoke);
static jni$_.Pointer<jni$_.Void> _$invokeMethod(
core$_.int $p,
jni$_.MethodInvocation $i,
) {
try {
final $d = $i.methodDescriptor.toDartString(releaseOriginal: true);
final $a = $i.args;
if ($d == r'run()V') {
_$impls[$p]!.run();
return jni$_.nullptr;
}
} catch (e) {
return jni$_.ProtectedJniExtensions.newDartException(e);
}
return jni$_.nullptr;
}
static void implementIn(
jni$_.JImplementer implementer,
$Runnable $impl,
) {
late final jni$_.RawReceivePort $p;
$p = jni$_.RawReceivePort(($m) {
if ($m == null) {
_$impls.remove($p.sendPort.nativePort);
$p.close();
return;
}
final $i = jni$_.MethodInvocation.fromMessage($m);
final $r = _$invokeMethod($p.sendPort.nativePort, $i);
jni$_.ProtectedJniExtensions.returnResult($i.result, $r);
});
implementer.add(
r'java.lang.Runnable',
$p,
_$invokePointer,
[
if ($impl.run$async) r'run()V',
],
);
final $a = $p.sendPort.nativePort;
_$impls[$a] = $impl;
}
factory Runnable.implement(
$Runnable $impl,
) {
final $i = jni$_.JImplementer();
implementIn($i, $impl);
return $i.implement<Runnable>();
}
}
extension Runnable$$Methods on Runnable {
static final _id_run = Runnable._class.instanceMethodId(
r'run',
r'()V',
);
static final _run =
jni$_.ProtectedJniExtensions.lookup<
jni$_.NativeFunction<
jni$_.JThrowablePtr Function(
jni$_.Pointer<jni$_.Void>,
jni$_.JMethodIDPtr,
)
>
>('globalEnv_CallVoidMethod')
.asFunction<
jni$_.JThrowablePtr Function(
jni$_.Pointer<jni$_.Void>,
jni$_.JMethodIDPtr,
)
>();
/// from: `public abstract void run()`
void run() {
final _$$selfRef = reference;
_run(_$$selfRef.pointer, _id_run.pointer).check();
}
}
abstract base mixin class $Runnable {
factory $Runnable({
required void Function() run,
core$_.bool run$async,
}) = _$Runnable;
void run();
core$_.bool get run$async => false;
}
final class _$Runnable with $Runnable {
_$Runnable({
required void Function() run,
this.run$async = false,
}) : _run = run;
final void Function() _run;
final core$_.bool run$async;
void run() {
return _run();
}
}
final class $Runnable$Type$ extends jni$_.JType<Runnable> {
@jni$_.internal
const $Runnable$Type$();
@jni$_.internal
@core$_.override
String get signature => r'Ljava/lang/Runnable;';
}
/// from: `com.example.piliplus.AndroidHelper`
extension type AndroidHelper._(jni$_.JObject _$this) implements jni$_.JObject {
static final _class = jni$_.JClass.forName(
r'com/example/piliplus/AndroidHelper',
);
/// The type which includes information such as the signature of this class.
static const jni$_.JType<AndroidHelper> type = $AndroidHelper$Type$();
static final _id_back = _class.staticMethodId(
r'back',
r'()V',
);
static final _back =
jni$_.ProtectedJniExtensions.lookup<
jni$_.NativeFunction<
jni$_.JThrowablePtr Function(
jni$_.Pointer<jni$_.Void>,
jni$_.JMethodIDPtr,
)
>
>('globalEnv_CallStaticVoidMethod')
.asFunction<
jni$_.JThrowablePtr Function(
jni$_.Pointer<jni$_.Void>,
jni$_.JMethodIDPtr,
)
>();
/// from: `static public void back()`
static void back() {
final _$$classRef = _class.reference;
_back(_$$classRef.pointer, _id_back.pointer).check();
}
static final _id_sdkInt = _class.staticMethodId(
r'sdkInt',
r'()I',
);
static final _sdkInt =
jni$_.ProtectedJniExtensions.lookup<
jni$_.NativeFunction<
jni$_.JniResult Function(
jni$_.Pointer<jni$_.Void>,
jni$_.JMethodIDPtr,
)
>
>('globalEnv_CallStaticIntMethod')
.asFunction<
jni$_.JniResult Function(
jni$_.Pointer<jni$_.Void>,
jni$_.JMethodIDPtr,
)
>();
/// from: `static public int sdkInt()`
static core$_.int sdkInt() {
final _$$classRef = _class.reference;
return _sdkInt(_$$classRef.pointer, _id_sdkInt.pointer).integer;
}
static final _id_openLinkVerifySettings = _class.staticMethodId(
r'openLinkVerifySettings',
r'()V',
);
static final _openLinkVerifySettings =
jni$_.ProtectedJniExtensions.lookup<
jni$_.NativeFunction<
jni$_.JThrowablePtr Function(
jni$_.Pointer<jni$_.Void>,
jni$_.JMethodIDPtr,
)
>
>('globalEnv_CallStaticVoidMethod')
.asFunction<
jni$_.JThrowablePtr Function(
jni$_.Pointer<jni$_.Void>,
jni$_.JMethodIDPtr,
)
>();
/// from: `static public void openLinkVerifySettings()`
static void openLinkVerifySettings() {
final _$$classRef = _class.reference;
_openLinkVerifySettings(
_$$classRef.pointer,
_id_openLinkVerifySettings.pointer,
).check();
}
static final _id_createShortcut = _class.staticMethodId(
r'createShortcut',
r'(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V',
);
static final _createShortcut =
jni$_.ProtectedJniExtensions.lookup<
jni$_.NativeFunction<
jni$_.JThrowablePtr Function(
jni$_.Pointer<jni$_.Void>,
jni$_.JMethodIDPtr,
jni$_.VarArgs<
(
jni$_.Pointer<jni$_.Void>,
jni$_.Pointer<jni$_.Void>,
jni$_.Pointer<jni$_.Void>,
jni$_.Pointer<jni$_.Void>,
)
>,
)
>
>('globalEnv_CallStaticVoidMethod')
.asFunction<
jni$_.JThrowablePtr Function(
jni$_.Pointer<jni$_.Void>,
jni$_.JMethodIDPtr,
jni$_.Pointer<jni$_.Void>,
jni$_.Pointer<jni$_.Void>,
jni$_.Pointer<jni$_.Void>,
jni$_.Pointer<jni$_.Void>,
)
>();
/// from: `static public void createShortcut(java.lang.String id, java.lang.String uri, java.lang.String label, java.lang.String icon)`
static void createShortcut(
jni$_.JString id,
jni$_.JString uri,
jni$_.JString label,
jni$_.JString icon,
) {
final _$$classRef = _class.reference;
final _$id = id.reference;
final _$uri = uri.reference;
final _$label = label.reference;
final _$icon = icon.reference;
_createShortcut(
_$$classRef.pointer,
_id_createShortcut.pointer,
_$id.pointer,
_$uri.pointer,
_$label.pointer,
_$icon.pointer,
).check();
}
}
final class $AndroidHelper$Type$ extends jni$_.JType<AndroidHelper> {
@jni$_.internal
const $AndroidHelper$Type$();
@jni$_.internal
@core$_.override
String get signature => r'Lcom/example/piliplus/AndroidHelper;';
}

View File

@@ -1,8 +1,9 @@
import 'package:PiliPlus/utils/android/bindings.g.dart';
import 'package:PiliPlus/utils/platform_utils.dart';
import 'package:flutter/widgets.dart' show WidgetsBinding, Size;
abstract final class DeviceUtils {
static late int sdkInt;
static final int sdkInt = AndroidHelper.sdkInt();
static bool get isTablet {
return size.shortestSide >= 600;

View File

@@ -46,11 +46,11 @@ abstract final class ReplyUtils {
required int type,
required int id,
required String message,
dynamic root,
dynamic parent,
dynamic ctime,
List? pictures,
dynamic mid,
required int root,
required int parent,
required int ctime,
required List pictures,
required int mid,
bool isManual = false,
}) async {
// CommAntifraud

View File

@@ -1,17 +1,13 @@
import 'dart:convert' show JsonEncoder, base64;
import 'dart:math' show Random;
import 'package:PiliPlus/common/constants.dart';
import 'package:catcher_2/catcher_2.dart';
import 'package:flutter/services.dart'
show Clipboard, ClipboardData, MethodChannel;
import 'package:flutter/services.dart' show Clipboard, ClipboardData;
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
abstract final class Utils {
static final random = Random();
static const channel = MethodChannel(Constants.appName);
static const jsonEncoder = JsonEncoder.withIndent(' ');
static final numericRegex = RegExp(r'^[\d\.]+$');

View File

@@ -269,6 +269,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.4"
cli_config:
dependency: transitive
description:
name: cli_config
sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec
url: "https://pub.dev"
source: hosted
version: "0.2.0"
cli_util:
dependency: transitive
description:
@@ -948,7 +956,7 @@ packages:
source: hosted
version: "0.6.1"
jni:
dependency: transitive
dependency: "direct main"
description:
name: jni
sha256: c2230682d5bc2362c1c9e8d3c7f406d9cbba23ab3f2e203a025dd47e0fb2e68f
@@ -963,6 +971,15 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.1"
jnigen:
dependency: "direct dev"
description:
path: "pkgs/jnigen"
ref: HEAD
resolved-ref: "14f4ce655c0cebb203777b8200303a9bc1f0b04e"
url: "https://github.com/dart-lang/native.git"
source: git
version: "0.17.0-wip"
js:
dependency: transitive
description:

View File

@@ -112,6 +112,7 @@ dependencies:
image_cropper: ^12.0.0
image_picker: ^1.1.2
intl: ^0.20.2
jni: ^1.0.0
json_annotation: ^4.11.0
live_photo_maker:
git:
@@ -244,6 +245,10 @@ dev_dependencies:
flutter_launcher_icons: ^0.14.4
flutter_lints: ^6.0.0
flutter_native_splash: ^2.4.6
jnigen:
git:
url: https://github.com/dart-lang/native.git
path: pkgs/jnigen
flutter_launcher_icons:
android: true

1
tool/README.md Normal file
View File

@@ -0,0 +1 @@
run `dart run tool/jnigen.dart`

23
tool/jnigen.dart Normal file
View File

@@ -0,0 +1,23 @@
import 'dart:io' show Platform;
import 'package:jnigen/jnigen.dart';
void main(List<String> args) {
final packageRoot = Platform.script.resolve('../');
generateJniBindings(
Config(
outputConfig: OutputConfig(
dartConfig: DartCodeOutputConfig(
path: packageRoot.resolve('lib/utils/android/bindings.g.dart'),
structure: .singleFile,
),
),
androidSdkConfig: AndroidSdkConfig(addGradleDeps: true),
sourcePath: [packageRoot.resolve('android/app/src/main/java')],
classes: [
'com.example.piliplus',
'java.lang.Runnable',
],
),
);
}