diff --git a/OpenHarmony.NDK.Bindings/ArkData/Preferences/Enums/PreferenceValueType.cs b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Enums/PreferenceValueType.cs new file mode 100644 index 0000000..461baae --- /dev/null +++ b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Enums/PreferenceValueType.cs @@ -0,0 +1,32 @@ +namespace OpenHarmony.NDK.Bindings; + +/// +/// 定义PreferencesValue的数据类型。 +/// +public enum PreferenceValueType +{ + /// + /// 空类型。 + /// + PREFERENCE_TYPE_NULL = 0, + + /// + /// 整型类型。 + /// + PREFERENCE_TYPE_INT, + + /// + /// 布尔类型。 + /// + PREFERENCE_TYPE_BOOL, + + /// + /// 字符串类型。 + /// + PREFERENCE_TYPE_STRING, + + /// + /// 结束类型。 + /// + PREFERENCE_TYPE_BUTT +} diff --git a/OpenHarmony.NDK.Bindings/ArkData/Preferences/Enums/PreferencesErrCode.cs b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Enums/PreferencesErrCode.cs new file mode 100644 index 0000000..d4f1d83 --- /dev/null +++ b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Enums/PreferencesErrCode.cs @@ -0,0 +1,52 @@ +namespace OpenHarmony.NDK.Bindings; + +/// +/// 声明首选项模块统一使用的错误码信息。 +/// +public enum PreferencesErrCode +{ + /// + /// 操作执行成功。 + /// + PREFERENCES_OK = 0, + + /// + /// 参数不合法。 + /// + PREFERENCES_ERROR_INVALID_PARAM = 401, + + /// + /// 系统能力不支持。 + /// + PREFERENCES_ERROR_NOT_SUPPORTED = 801, + + /// + /// 基准错误码。 + /// + PREFERENCES_ERROR_BASE = 15500000, + + /// + /// 删除文件失败。 + /// + PREFERENCES_ERROR_DELETE_FILE = 15500010, + + /// + /// 存储异常。 + /// + PREFERENCES_ERROR_STORAGE = 15500011, + + /// + /// 申请内存失败。 + /// + PREFERENCES_ERROR_MALLOC = 15500012, + + /// + /// Key不存在。 + /// + PREFERENCES_ERROR_KEY_NOT_FOUND = 15500013, + + /// + /// 获取数据变更订阅服务失败。 + /// + PREFERENCES_ERROR_GET_DATAOBSMGRCLIENT = 15500019 +} diff --git a/OpenHarmony.NDK.Bindings/ArkData/Preferences/Enums/PreferencesStorageType.cs b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Enums/PreferencesStorageType.cs new file mode 100644 index 0000000..5657d9b --- /dev/null +++ b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Enums/PreferencesStorageType.cs @@ -0,0 +1,17 @@ +namespace OpenHarmony.NDK.Bindings; + +/// +/// 首选项配置选项的存储模式枚举。 +/// +public enum PreferencesStorageType +{ + /// + /// XML存储模式,对数据的操作发生在内存中,调用OH_Preferences_Close时落盘,不支持多进程。 + /// + PREFERENCES_STORAGE_XML = 0, + + /// + /// GSKV存储模式,对数据的操作实时落盘,可支持多进程 + /// + PREFERENCES_STORAGE_GSKV, +} diff --git a/OpenHarmony.NDK.Bindings/ArkData/Preferences/Managed/Preferences.cs b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Managed/Preferences.cs new file mode 100644 index 0000000..1521f7c --- /dev/null +++ b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Managed/Preferences.cs @@ -0,0 +1,391 @@ +using System.Runtime.InteropServices; + +using OpenHarmony.NDK.Bindings.Native; + +namespace OpenHarmony.NDK.Bindings; + +/// +/// 表示首选项数据变更的委托 +/// +/// 发生变更的键列表 +public delegate void PreferencesDataChangedHandler(PreferencesPair keys); + +/// +/// 提供访问 对象的接口与数据结构。 +/// +public unsafe partial class Preferences : IDisposable +{ + /// + /// 指向原生Preferences实例的指针。 + /// + internal OH_Preferences* NativeInstance; + + /// + /// 存储注册的观察者回调 + /// + private static readonly Dictionary _observers = []; + + /// + /// 用于生成订阅唯一标识符的计数器 + /// + private static ulong _nextId = 0; + + /// + /// 指示是否已释放资源。 + /// + private bool _disposedValue; + + private Preferences(OH_Preferences* preferences) + { + NativeInstance = preferences; + } + + /// + /// 打开一个Preferences实例对象并创建指向它的指针。当不再需要使用指针时,请使用OH_Preferences_Close关闭实例对象。 + /// + /// + /// + /// + public static Preferences Open(PreferencesOption option, ref int errCode) + { + fixed (int* errCodePtr = &errCode) + { + var preferences = OH_NativeApi.OH_Preferences_Open(option.NativeInstance, errCodePtr); + + return new Preferences(preferences); + } + } + + /// + /// 关闭一个Preferences实例对象。 + /// + /// + /// + public int Close() + { + return OH_NativeApi.OH_Preferences_Close(NativeInstance); + } + + /// + /// 获取Preferences实例对象中Key对应的整型值。 + /// + /// + /// + /// + public int GetInt(string key, ref int value) + { + using var keyPtr = key.ToPointer(); + fixed (int* valuePtr = &value) + { + return OH_NativeApi.OH_Preferences_GetInt(NativeInstance, keyPtr, valuePtr); + } + } + + /// + /// 获取Preferences实例对象中Key对应的布尔值。 + /// + /// + /// + /// + public int GetBool(string key, ref bool value) + { + using var keyPtr = key.ToPointer(); + fixed (bool* valuePtr = &value) + { + return OH_NativeApi.OH_Preferences_GetBool(NativeInstance, keyPtr, valuePtr); + } + } + + /// + /// 获取Preferences实例对象中Key对应的字符串。 + /// + /// + /// + /// + public int GetString(string key, ref string value) + { + using var keyPtr = key.ToPointer(); + char* stringPtr = null; + uint stringLen = 0; + + // 调用正确的底层方法 + int result = OH_NativeApi.OH_Preferences_GetString(NativeInstance, key, &stringPtr, &stringLen); + + if (result == 0 && stringPtr != null) + { + // 将 char* 转换为 managed string + value = Marshal.PtrToStringUTF8((IntPtr)stringPtr, (int)stringLen); + + // 释放原生字符串内存 + OH_NativeApi.OH_Preferences_FreeString(stringPtr); + } + + return result; + } + + /* 此处由于不向C#传递非托管string, 因此不再需要释放 + /// + /// 释放从Preferences实例对象中获取的字符串。 + /// + /// + /// + public void OH_Preferences_FreeString(char* @string); + */ + + /// + /// 根据Key设置Preferences实例对象中的整型值。 + /// + /// + /// + /// + public int SetInt(string key, int value) + { + using var keyPtr = key.ToPointer(); + return OH_NativeApi.OH_Preferences_SetInt(NativeInstance, keyPtr, value); + } + + /// + /// 根据Key设置Preferences实例对象中的布尔值。 + /// + /// + /// + /// + public int SetBool(string key, bool value) + { + using var keyPtr = key.ToPointer(); + return OH_NativeApi.OH_Preferences_SetBool(NativeInstance, keyPtr, value); + } + + /// + /// 根据Key设置Preferences实例对象中的字符串。 + /// + /// + /// + /// + public int SetString(string key, string value) + { + using var keyPtr = key.ToPointer(); + using var valuePtr = value.ToPointer(); + return OH_NativeApi.OH_Preferences_SetString(NativeInstance, keyPtr, valuePtr); + } + + /// + /// 在Preferences实例对象中删除Key对应的KV数据。 + /// + /// + /// + public int Delete(string key) + { + using var keyPtr = key.ToPointer(); + return OH_NativeApi.OH_Preferences_Delete(NativeInstance, keyPtr); + } + + /// + /// 本地回调的静态桥接方法 + /// + /// + /// + /// + /// + private static unsafe void NativeObserverCallback(ulong id, void* context, OH_PreferencesPair* keys, uint count) + { + if (_observers.TryGetValue(id, out var observerData)) + { + var pairs = new PreferencesPair(keys, count); + // 调用托管回调 + observerData.Callback?.Invoke(pairs); + } + } + + /// + /// 对选取的Key注册数据变更订阅。订阅的Key的值发生变更后,在调用OH_Preferences_Close()后触发回调。 + /// + /// 当数据变更时要执行的回调 + /// 要监听的键数组 + /// 操作结果代码,0表示成功 + public unsafe int RegisterDataObserver(PreferencesDataChangedHandler callback, string[] keys) + { + if (keys == null || keys.Length == 0 || callback == null) + { + return (int)PreferencesErrCode.PREFERENCES_ERROR_INVALID_PARAM; + } + + // 创建唯一的回调标识符 + var id = Interlocked.Increment(ref _nextId); + + // 创建并存储静态委托实例,防止被垃圾回收 + OH_PreferencesDataObserver nativeCallback = new((context, pairs, count) => NativeObserverCallback(id, context, pairs, count)); + var observerHandle = Marshal.GetFunctionPointerForDelegate(nativeCallback); + + // 存储回调和委托句柄以防垃圾回收 + _observers[id] = (callback, nativeCallback, observerHandle); + + // 创建非托管字符串数组 + char*[] unmanagedKeys = new char*[keys.Length]; + + try + { + // 为每个字符串分配内存并复制 + for (int i = 0; i < keys.Length; i++) + { + if (keys[i] != null) + { + using var ptr = keys[i].ToPointer(); + var keyPtr = (char*)ptr.Pointer; + int len = keys[i].Length; + unmanagedKeys[i] = (char*)Marshal.AllocHGlobal((len + 1) * sizeof(char)); + for (int j = 0; j < len; j++) + { + unmanagedKeys[i][j] = keyPtr[j]; + } + unmanagedKeys[i][len] = '\0'; + } + } + + return OH_NativeApi.OH_Preferences_RegisterDataObserver(NativeInstance, null, observerHandle, unmanagedKeys, (uint)keys.Length); + } + catch + { + // 发生异常时,清理资源 + if (_observers.TryGetValue(id, out var observerData)) + { + _observers.Remove(id); + } + return -1; + } + finally + { + // 释放分配的内存 + for (int i = 0; i < unmanagedKeys.Length; i++) + { + if (unmanagedKeys[i] != null) + { + Marshal.FreeHGlobal((IntPtr)unmanagedKeys[i]); + } + } + } + } + + /// + /// 取消注册选取Key的数据变更订阅。 + /// + /// 之前注册的回调 + /// 要取消监听的键数组 + /// 操作结果代码,0表示成功 + public unsafe int UnregisterDataObserver(PreferencesDataChangedHandler callback, string[] keys) + { + if (keys == null || keys.Length == 0 || callback == null) + { + Hilog.OH_LOG_DEBUG(LogType.LOG_APP, "Preferences", $"UnregisterDataObserver: Invalid parameters, {keys == null} {keys?.Length == 0} {callback == null} "); + return (int)PreferencesErrCode.PREFERENCES_ERROR_INVALID_PARAM; + } + + // 查找对应的上下文标识符 + ulong? contextToRemove = null; + foreach (var entry in _observers) + { + if (entry.Value.Callback == callback) + { + contextToRemove = entry.Key; + break; + } + } + + if (!contextToRemove.HasValue) + { + // 未找到匹配的观察者 + return (int)PreferencesErrCode.PREFERENCES_OK; + } + + // 创建非托管字符串数组 + char*[] unmanagedKeys = new char*[keys.Length]; + + try + { + // 为每个字符串分配内存并复制 + for (int i = 0; i < keys.Length; i++) + { + if (keys[i] != null) + { + using var ptr = keys[i].ToPointer(); + var keyPtr = (char*)ptr.Pointer; + int len = keys[i].Length; + unmanagedKeys[i] = (char*)Marshal.AllocHGlobal((len + 1) * sizeof(char)); + for (int j = 0; j < len; j++) + { + unmanagedKeys[i][j] = keyPtr[j]; + } + unmanagedKeys[i][len] = '\0'; + + } + } + + // 获取与此回调关联的原生委托 + if (_observers.TryGetValue(contextToRemove.Value, out var observerData)) + { + int result = OH_NativeApi.OH_Preferences_UnregisterDataObserver(NativeInstance, null, observerData.ObserverHandle, unmanagedKeys, (uint)keys.Length); + + // 释放委托句柄并从字典中移除 + _observers.Remove(contextToRemove.Value); + return result; + } + + return (int)PreferencesErrCode.PREFERENCES_ERROR_INVALID_PARAM; ; + } + finally + { + // 释放分配的内存 + for (int i = 0; i < unmanagedKeys.Length; i++) + { + if (unmanagedKeys[i] != null) + { + Marshal.FreeHGlobal((IntPtr)unmanagedKeys[i]); + } + } + } + } + + /// + /// 校验当前平台是否支持对应存储模式。 + /// + /// + /// + /// + public int IsStorageTypeSupported(PreferencesStorageType type, ref bool isSupported) + { + fixed (bool* isSupportedPtr = &isSupported) + { + return OH_NativeApi.OH_Preferences_IsStorageTypeSupported(type, isSupportedPtr); + } + } + + protected virtual void Dispose(bool disposing) + { + if (!_disposedValue) + { + if (disposing) + { + // TODO: 释放托管状态(托管对象) + + } + + // TODO: 释放未托管的资源(未托管的对象)并重写终结器 + // TODO: 将大型字段设置为 null + _disposedValue = true; + } + } + + // TODO: 仅当“Dispose(bool disposing)”拥有用于释放未托管资源的代码时才替代终结器 + ~Preferences() + { + // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中 + Dispose(disposing: false); + } + + public void Dispose() + { + // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中 + Dispose(disposing: true); + GC.SuppressFinalize(this); + } +} diff --git a/OpenHarmony.NDK.Bindings/ArkData/Preferences/Managed/PreferencesOption.cs b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Managed/PreferencesOption.cs new file mode 100644 index 0000000..82976da --- /dev/null +++ b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Managed/PreferencesOption.cs @@ -0,0 +1,127 @@ +namespace OpenHarmony.NDK.Bindings; + +/// +/// 提供访问 对象的接口与数据结构。 +/// +public unsafe partial class PreferencesOption : IDisposable +{ + internal OH_PreferencesOption* NativeInstance; + private bool _disposedValue; + + /// + /// 创建一个Preferences配置选项。当不再需要使用时,请使用Destroy销毁实例对象,否则会导致内存泄漏。 + /// + public PreferencesOption() + { + NativeInstance = OH_NativeApi.OH_PreferencesOption_Create(); + } + + /// + /// 设置Preferences配置选项的文件名称。 + /// + /// + /// + public int SetFileName(string fileName) + { + ObjectDisposedException.ThrowIf(_disposedValue, this); + + fixed (char* fileNameBuffer = fileName) + { + return OH_NativeApi.OH_PreferencesOption_SetFileName(NativeInstance, fileNameBuffer); + } + } + + /// + /// 设置Preferences配置选项的包名称。 + /// + /// + /// + public int SetBundleName(string bundleName) + { + ObjectDisposedException.ThrowIf(_disposedValue, this); + + fixed (char* bundleNameBuffer = bundleName) + { + return OH_NativeApi.OH_PreferencesOption_SetBundleName(NativeInstance, bundleNameBuffer); + } + } + + /// + /// 设置Preferences配置选项的应用组ID。设置应用组ID后,会指定在此应用组ID对应的沙箱路径下创建Preferences实例。应用组ID需要向应用市场获取,暂不支持。当传入的应用组ID为空字符串时,默认在本应用沙箱目录下创建Preferences实例。 + /// + /// + /// + public int SetDataGroupId(string dataGroupId) + { + ObjectDisposedException.ThrowIf(_disposedValue, this); + + fixed (char* dataGroupIdBuffer = dataGroupId) + { + return OH_NativeApi.OH_PreferencesOption_SetDataGroupId(NativeInstance, dataGroupIdBuffer); + } + } + + /// + /// 设置Preferences实例的存储模式。 + /// + /// + /// + public int SetStorageType(PreferencesStorageType type) + { + ObjectDisposedException.ThrowIf(_disposedValue, this); + + return OH_NativeApi.OH_PreferencesOption_SetStorageType(NativeInstance, type); + } + + /// + /// 销毁Preferences配置选项实例。 + /// + /// + public int Destroy() + { + if (null != NativeInstance) + { + var retCode = OH_NativeApi.OH_PreferencesOption_Destroy(NativeInstance); + NativeInstance = null; + return retCode; + } + + return 0; + } + + protected virtual void Dispose(bool disposing) + { + if (!_disposedValue) + { + if (disposing) + { + // TODO: 释放托管状态(托管对象) + } + + // TODO: 释放未托管的资源(未托管的对象)并重写终结器 + // TODO: 将大型字段设置为 null + + if (null != NativeInstance) + { + _ = OH_NativeApi.OH_PreferencesOption_Destroy(NativeInstance); + NativeInstance = null; + } + + _disposedValue = true; + } + } + + // TODO: 仅当“Dispose(bool disposing)”拥有用于释放未托管资源的代码时才替代终结器 + ~PreferencesOption() + { + // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中 + Dispose(disposing: false); + } + + public void Dispose() + { + // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中 + Dispose(disposing: true); + GC.SuppressFinalize(this); + } +} diff --git a/OpenHarmony.NDK.Bindings/ArkData/Preferences/Managed/PreferencesPair.cs b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Managed/PreferencesPair.cs new file mode 100644 index 0000000..43ddb4a --- /dev/null +++ b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Managed/PreferencesPair.cs @@ -0,0 +1,131 @@ +using System.Runtime.InteropServices; + +namespace OpenHarmony.NDK.Bindings; + +/// +/// 提供访问 对象的接口与数据结构。 +/// +public unsafe partial class PreferencesPair +{ + internal OH_PreferencesPair* NativeInstance; + + /// + /// 创建一个 PreferencesPair 实例 + /// + /// 原生键值对数组指针 + /// 键值对数量 + public PreferencesPair(OH_PreferencesPair* nativePairs, uint count) + { + NativeInstance = nativePairs; + Count = count; + } + + /// + /// 键值对的数量 + /// + public uint Count { get; } + + /// + /// 获取指定索引位置的键。 + /// + /// 索引位置 + /// 键的字符串,如果失败返回null + public string? GetKey(uint index) + { + if (NativeInstance == null || index >= Count) + { + return null; + } + + char* keyPtr = OH_NativeApi.OH_PreferencesPair_GetKey(NativeInstance, index); + return Marshal.PtrToStringUTF8((IntPtr)keyPtr); + } + + /// + /// 获取指定索引位置的值。 + /// + /// 索引位置 + /// + public PreferencesValue? GetValue(uint index) + { + if (NativeInstance == null || index >= Count) + { + return null; + } + + OH_PreferencesValue* valuePtr = OH_NativeApi.OH_PreferencesPair_GetPreferencesValue(NativeInstance, index); + if (valuePtr == null) + { + return null; + } + + return new PreferencesValue(valuePtr); + } +} + +/// +/// 提供对 的扩展方法。 +/// +public static class PreferencesPairExtensions +{ + /// + /// 获取指定索引位置的值类型。 + /// + /// 索引位置 + /// 值的类型 + public unsafe static PreferenceValueType GetValueType(this PreferencesPair pairs, uint index) + { + if (pairs == null || pairs.NativeInstance == null || index >= pairs.Count) + { + return PreferenceValueType.PREFERENCE_TYPE_NULL; + } + + OH_PreferencesValue* valuePtr = OH_NativeApi.OH_PreferencesPair_GetPreferencesValue(pairs.NativeInstance, index); + if (valuePtr == null) + { + return PreferenceValueType.PREFERENCE_TYPE_NULL; + } + + return OH_NativeApi.OH_PreferencesValue_GetValueType(valuePtr); + } + + /// + /// 获取指定索引位置的值。 + /// + /// PreferencesPair 实例 + /// 索引位置 + /// + public unsafe static (string key, PreferenceValueType type, object? value) GetValue(this PreferencesPair pairs, uint index) + { + if (pairs == null || pairs.NativeInstance == null || index >= pairs.Count) + { + return (string.Empty, PreferenceValueType.PREFERENCE_TYPE_NULL, null); + } + string key = pairs.GetKey(index) ?? string.Empty; + PreferenceValueType type = pairs.GetValueType(index); + PreferencesValue? value = pairs.GetValue(index); + object? valueData = null; + if (value != null) + { + switch (type) + { + case PreferenceValueType.PREFERENCE_TYPE_INT: + int intValue = 0; + value.GetInt(ref intValue); + valueData = intValue; + break; + case PreferenceValueType.PREFERENCE_TYPE_BOOL: + bool boolValue = false; + value.GetBool(ref boolValue); + valueData = boolValue; + break; + case PreferenceValueType.PREFERENCE_TYPE_STRING: + string stringValue = string.Empty; + value.GetString(ref stringValue); + valueData = stringValue; + break; + } + } + return (key, type, valueData); + } +} diff --git a/OpenHarmony.NDK.Bindings/ArkData/Preferences/Managed/PreferencesValue.cs b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Managed/PreferencesValue.cs new file mode 100644 index 0000000..9f065ae --- /dev/null +++ b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Managed/PreferencesValue.cs @@ -0,0 +1,96 @@ +using System.Runtime.InteropServices; + +namespace OpenHarmony.NDK.Bindings; + +/// +/// 提供访问 对象的接口与数据结构。 +/// +public unsafe partial class PreferencesValue +{ + internal OH_PreferencesValue* NativeInstance; + + /// + /// 创建一个 PreferencesValue 实例 + /// + /// 原生 PreferencesValue 指针 + internal PreferencesValue(OH_PreferencesValue* nativeValue) + { + NativeInstance = nativeValue; + } + + /// + /// 获取当前值的数据类型。 + /// + /// 值的数据类型 + public PreferenceValueType GetValueType() + { + if (NativeInstance == null) + { + return PreferenceValueType.PREFERENCE_TYPE_NULL; + } + + return OH_NativeApi.OH_PreferencesValue_GetValueType(NativeInstance); + } + + /// + /// 获取整型值。 + /// + /// 输出的整型值 + /// 操作结果,0表示成功 + public int GetInt(ref int value) + { + if (NativeInstance == null) + { + return (int)PreferencesErrCode.PREFERENCES_ERROR_INVALID_PARAM; + } + + fixed (int* valuePtr = &value) + { + return OH_NativeApi.OH_PreferencesValue_GetInt(NativeInstance, valuePtr); + } + } + + /// + /// 获取布尔值。 + /// + /// 输出的布尔值 + /// 操作结果,0表示成功 + public int GetBool(ref bool value) + { + if (NativeInstance == null) + { + return (int)PreferencesErrCode.PREFERENCES_ERROR_INVALID_PARAM; + } + + fixed (bool* valuePtr = &value) + { + return OH_NativeApi.OH_PreferencesValue_GetBool(NativeInstance, valuePtr); + } + } + + /// + /// 获取字符串值。 + /// + /// 输出的字符串值 + /// 操作结果,0表示成功 + public int GetString(ref string value) + { + if (NativeInstance == null) + { + return (int)PreferencesErrCode.PREFERENCES_ERROR_INVALID_PARAM; + } + + char* stringPtr = null; + uint stringLen = 0; + + int result = OH_NativeApi.OH_PreferencesValue_GetString(NativeInstance, &stringPtr, &stringLen); + + if (result == 0 && stringPtr != null) + { + // 将 char* 转换为 managed string + value = Marshal.PtrToStringUTF8((IntPtr)stringPtr, (int)stringLen); + } + + return result; + } +} diff --git a/OpenHarmony.NDK.Bindings/ArkData/Preferences/Native/OH_NativeApi.cs b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Native/OH_NativeApi.cs new file mode 100644 index 0000000..ca79a4a --- /dev/null +++ b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Native/OH_NativeApi.cs @@ -0,0 +1,237 @@ +using System.Runtime.InteropServices; + +namespace OpenHarmony.NDK.Bindings +{ + /// + /// 提供 OpenHarmony NativeApi 的 P/Invoke 方法封装 + /// + public static unsafe partial class OH_NativeApi + { + #region OH_Preferences + + /// + /// 打开一个Preferences实例对象并创建指向它的指针。当不再需要使用指针时,请使用OH_Preferences_Close关闭实例对象。 + /// + /// + /// + /// + [LibraryImport("libohpreferences.so")] + public static partial OH_Preferences* OH_Preferences_Open(OH_PreferencesOption* option, int* errCode); + + /// + /// 关闭一个Preferences实例对象。 + /// + /// + /// + [LibraryImport("libohpreferences.so")] + public static partial int OH_Preferences_Close(OH_Preferences* preference); + /// + /// 获取Preferences实例对象中Key对应的整型值。 + /// + /// + /// + /// + [LibraryImport("libohpreferences.so")] + public static partial int OH_Preferences_GetInt(OH_Preferences* preference, char* key, int* value); + + /// + /// 获取Preferences实例对象中Key对应的布尔值。 + /// + /// + /// + /// + [LibraryImport("libohpreferences.so")] + public static partial int OH_Preferences_GetBool(OH_Preferences* preference, char* key, bool* value); + + /// + /// 获取Preferences实例对象中Key对应的字符串。 + /// + /// + /// + /// + [LibraryImport("libohpreferences.so", StringMarshalling = StringMarshalling.Utf8)] + public static partial int OH_Preferences_GetString(OH_Preferences* preference, string key, char** value, uint* valueLen); + + /// + /// 释放从Preferences实例对象中获取的字符串。 + /// + /// + /// + [LibraryImport("libohpreferences.so")] + public static partial void OH_Preferences_FreeString(char* @string); + + /// + /// 根据Key设置Preferences实例对象中的整型值。 + /// + /// + /// + /// + [LibraryImport("libohpreferences.so")] + public static partial int OH_Preferences_SetInt(OH_Preferences* preference, char* key, int value); + + /// + /// 根据Key设置Preferences实例对象中的布尔值。 + /// + /// + /// + /// + [LibraryImport("libohpreferences.so")] + public static partial int OH_Preferences_SetBool(OH_Preferences* preference, char* key, [MarshalAs(UnmanagedType.Bool)] bool value); + + /// + /// 根据Key设置Preferences实例对象中的字符串。 + /// + /// + /// + /// + [LibraryImport("libohpreferences.so")] + public static partial int OH_Preferences_SetString(OH_Preferences* preference, char* key, char* value); + + /// + /// 在Preferences实例对象中删除Key对应的KV数据。 + /// + /// + /// + /// + [LibraryImport("libohpreferences.so")] + public static partial int OH_Preferences_Delete(OH_Preferences* preference, char* key); + + /// + /// 对选取的Key注册数据变更订阅。订阅的Key的值发生变更后,在调用OH_Preferences_Close()后触发回调。 + /// + /// + /// + /// + /// + /// + /// + [LibraryImport("libohpreferences.so")] + public static partial int OH_Preferences_RegisterDataObserver(OH_Preferences* preference, void* context, IntPtr observer, char*[] keys, uint keyCount); + + /// + /// 取消注册选取Key的数据变更订阅。 + /// + /// + /// + /// + /// + /// + /// + [LibraryImport("libohpreferences.so")] + public static partial int OH_Preferences_UnregisterDataObserver(OH_Preferences* preference, void* context, IntPtr observer, char*[] keys, uint keyCount); + + /// + /// 校验当前平台是否支持对应存储模式。 + /// + /// + /// + /// + [LibraryImport("libohpreferences.so")] + public static partial int OH_Preferences_IsStorageTypeSupported(PreferencesStorageType type, bool* isSupported); + #endregion + + #region OH_PreferencesOption + + /// + /// 创建一个Preferences配置选项的OH_PreferencesOption实例对象以及指向它的指针。当不再需要使用指针时,请使用OH_PreferencesOption_Destroy销毁实例对象,否则会导致内存泄漏。 + /// + /// + /// + [LibraryImport("libohpreferences.so")] + public static partial OH_PreferencesOption* OH_PreferencesOption_Create(); + + /// + /// 设置Preferences配置选项OH_PreferencesOption实例对象的文件名称。 + /// + /// + /// + /// + [LibraryImport("libohpreferences.so")] + public static partial int OH_PreferencesOption_SetFileName(OH_PreferencesOption* option, char* fileName); + + /// + /// 设置Preferences配置选项OH_PreferencesOption实例对象的包名称。 + /// + /// + /// + /// + [LibraryImport("libohpreferences.so")] + public static partial int OH_PreferencesOption_SetBundleName(OH_PreferencesOption* option, char* bundleName); + + /// + /// 设置Preferences配置选项OH_PreferencesOption实例对象的应用组ID。设置应用组ID后,会指定在此应用组ID对应的沙箱路径下创建Preferences实例。应用组ID需要向应用市场获取,暂不支持。当传入的应用组ID为空字符串时,默认在本应用沙箱目录下创建Preferences实例。 + /// + /// + /// + /// + [LibraryImport("libohpreferences.so")] + public static partial int OH_PreferencesOption_SetDataGroupId(OH_PreferencesOption* option, char* dataGroupId); + + /// + /// 设置Preferences实例对象的存储模式。 + /// + /// + /// + /// + [LibraryImport("libohpreferences.so")] + public static partial int OH_PreferencesOption_SetStorageType(OH_PreferencesOption* option, PreferencesStorageType type); + + /// + /// 销毁Preferences配置选项OH_PreferencesOption实例。 + /// + /// + /// + [LibraryImport("libohpreferences.so")] + public static partial int OH_PreferencesOption_Destroy(OH_PreferencesOption* option); + + #endregion + + #region OH_PreferencesPair + + /// + /// 获取KV数据中索引对应数据的键。 + /// + [LibraryImport("libohpreferences.so")] + public static partial char* OH_PreferencesPair_GetKey(OH_PreferencesPair* pairs, uint index); + + /// + /// 获取KV数据数组中索引对应的值。 + /// + [LibraryImport("libohpreferences.so")] + public static partial OH_PreferencesValue* OH_PreferencesPair_GetPreferencesValue(OH_PreferencesPair* pairs, uint index); + + #endregion + + #region OH_PreferencesValue + + /// + /// 获取PreferencesValue对象的数据类型。 + /// + /// + [LibraryImport("libohpreferences.so")] + public static partial PreferenceValueType OH_PreferencesValue_GetValueType(OH_PreferencesValue* @object); + + /// + /// 从PreferencesValue对象OH_PreferencesValue中获取一个整型值。 + /// + /// + [LibraryImport("libohpreferences.so")] + public static partial int OH_PreferencesValue_GetInt(OH_PreferencesValue* @object, int* value); + + /// + /// 从PreferencesValue对象OH_PreferencesValue中获取一个布尔值。 + /// + /// + [LibraryImport("libohpreferences.so")] + public static partial int OH_PreferencesValue_GetBool(OH_PreferencesValue* @object, bool* value); + + /// + /// 从PreferencesValue对象OH_PreferencesValue中获取字符串。 + /// + /// + [LibraryImport("libohpreferences.so")] + public static partial int OH_PreferencesValue_GetString(OH_PreferencesValue* @object, char** value, uint* valueLen); + + #endregion + } +} diff --git a/OpenHarmony.NDK.Bindings/ArkData/Preferences/Native/OH_Preferences.cs b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Native/OH_Preferences.cs new file mode 100644 index 0000000..4449c82 --- /dev/null +++ b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Native/OH_Preferences.cs @@ -0,0 +1,18 @@ +using System.Runtime.InteropServices; + +namespace OpenHarmony.NDK.Bindings; + +/// +/// 定义Preferences对象类型。 +/// +[StructLayout(LayoutKind.Sequential)] +public struct OH_Preferences; + +/// +/// Preferences数据变更观察者回调函数类型。 +/// +/// 用户上下文数据 +/// 变更的键值对数组 +/// 变更的键值对数量 +[UnmanagedFunctionPointer(CallingConvention.Cdecl)] +public unsafe delegate void OH_PreferencesDataObserver(void* context, OH_PreferencesPair* pairs, uint count); diff --git a/OpenHarmony.NDK.Bindings/ArkData/Preferences/Native/OH_PreferencesOption.cs b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Native/OH_PreferencesOption.cs new file mode 100644 index 0000000..894b69e --- /dev/null +++ b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Native/OH_PreferencesOption.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace OpenHarmony.NDK.Bindings; + +/// +/// 定义Preferences配置选项的数据结构。 +/// +[StructLayout(LayoutKind.Sequential)] +public struct OH_PreferencesOption; diff --git a/OpenHarmony.NDK.Bindings/ArkData/Preferences/Native/OH_PreferencesPair.cs b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Native/OH_PreferencesPair.cs new file mode 100644 index 0000000..94ee640 --- /dev/null +++ b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Native/OH_PreferencesPair.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace OpenHarmony.NDK.Bindings; + +/// +/// 定义Preferences使用的KV数据对象类型。 +/// +[StructLayout(LayoutKind.Sequential)] +public struct OH_PreferencesPair; diff --git a/OpenHarmony.NDK.Bindings/ArkData/Preferences/Native/OH_PreferencesValue.cs b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Native/OH_PreferencesValue.cs new file mode 100644 index 0000000..d2ff127 --- /dev/null +++ b/OpenHarmony.NDK.Bindings/ArkData/Preferences/Native/OH_PreferencesValue.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace OpenHarmony.NDK.Bindings; + +/// +/// 定义PreferencesValue对象类型。 +/// +[StructLayout(LayoutKind.Sequential)] +public struct OH_PreferencesValue; diff --git a/OpenHarmony.NDK.Bindings/Extension/DisposablePointer.cs b/OpenHarmony.NDK.Bindings/Extension/DisposablePointer.cs new file mode 100644 index 0000000..4462bb6 --- /dev/null +++ b/OpenHarmony.NDK.Bindings/Extension/DisposablePointer.cs @@ -0,0 +1,108 @@ +using System.Runtime.InteropServices; + +namespace OpenHarmony.NDK.Bindings +{ + /// + /// 提供字符串到 的转换扩展方法 + /// + public static class DisposablePointerExtension + { + /// + /// 将字符串转换为 ,分配非托管内存 + /// + /// + /// + public static DisposablePointer ToPointer(this string str) + { + if (str == null) + { + return new DisposablePointer(IntPtr.Zero); + } + + // 分配非托管内存 + IntPtr ptr = Marshal.StringToHGlobalAnsi(str); + return new DisposablePointer(ptr); + } + } + + /// + /// MarshalPtr类用于管理非托管内存的分配和释放 + /// + public class DisposablePointer : IDisposable + { + /// + /// 指示是否已释放资源 + /// + private bool _disposedValue; + + /// + /// 指向分配的非托管内存的指针 + /// + public IntPtr Pointer { get; private set; } + + /// + /// 构造函数,初始化指针 + /// + /// 非托管内存的指针 + public DisposablePointer(IntPtr ptr) + { + Pointer = ptr; + } + + /// + /// 提供从DisposablePointer到IntPtr的隐式转换 + /// + /// 可释放的指针对象 + public static implicit operator IntPtr(DisposablePointer disposablePointer) + { + return disposablePointer?.Pointer ?? IntPtr.Zero; + } + + /// + /// 提供从DisposablePointer到char*的隐式转换 + /// + /// 可释放的指针对象 + public static unsafe implicit operator char*(DisposablePointer disposablePointer) + { + if (disposablePointer == null || disposablePointer.Pointer == IntPtr.Zero) + { + return null; + } + + return (char*)disposablePointer.Pointer; + } + + protected virtual void Dispose(bool disposing) + { + if (!_disposedValue) + { + if (Pointer != IntPtr.Zero) + { + // 释放分配的非托管内存 + Marshal.FreeHGlobal(Pointer); + + // 将指针重置为零 + Pointer = IntPtr.Zero; + } + + _disposedValue = true; + } + } + + /// + /// 析构函数,释放非托管资源 + /// + ~DisposablePointer() + { + // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中 + Dispose(disposing: false); + } + + public void Dispose() + { + // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中 + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +}