清除以下文件夹即可：/Users/[your name]/Library/MobileDevice/Provisioning Profiles
前言在开发一个需要Native代码的jar包的时候，我们可以单独编译Native代码成so库，而不需要使用Android Studio进行编译，这样在开发通用Native代码的时候可以节省很多时间。设置环境变量设置ANDROID_HOME/ANDROID_SDK_HOME变量，该目录为安装Android Studio时候设置的SDK目录，比如我的目录为D:\Library\Android\sdk，那么设置该变量为此地址即可。编译脚本build.bat：set abi=arm64-v8a if not exist %abi% md %abi% cd %abi% %ANDROID_SDK_HOME%/cmake/3.22.1/bin/cmake ^ -DANDROID_ABI=%abi% ^ -DANDROID_NDK=%ANDROID_SDK_HOME%/ndk/25.1.8937393 ^ -DCMAKE_BUILD_TYPE=Debug ^ -DCMAKE_TOOLCHAIN_FILE=%ANDROID_SDK_HOME%/ndk/25.1.8937393/build/cmake/android.toolchain.cmake ^ -DANDROID_NATIVE_API_LEVEL=19 ^ -DANDROID_TOOLCHAIN=clang -DCMAKE_GENERATOR="Ninja" ^ -DCMAKE_MAKE_PROGRAM=%ANDROID_SDK_HOME%/cmake/3.22.1/bin/ninja ^ .. %ANDROID_SDK_HOME%/cmake/3.22.1/bin/ninja cd ..以上脚本参考自Ref 1，做了一些简单的错误更正和微调，其中DANDROID_NDK的设置需要定位到D:\Library\Android\sdk\ndk\25.1.8937393，而不是内层的build目录。针对MacOS平台：#!/usr/bin/env sh echo "========== Compile Android *.so ==========" abi="arm64-v8a" NDK_VERSION="27.0.11718014" ANDROID_SDK_HOME="/Users/winter/Library/Android/sdk" ANDROID_NDK_PATH="$ANDROID_SDK_HOME/ndk/$NDK_VERSION" CMAKE_VERSION="3.22.1" if [ ! -d "bins" ]; then mkdir "bins" fi cd bins # bins/arm64-v8a if [ ! -d $abi ]; then mkdir $abi fi cd $abi $ANDROID_SDK_HOME/cmake/$CMAKE_VERSION/bin/cmake \ -DANDROID_ABI=$abi \ -DANDROID_NDK=$ANDROID_NDK_PATH \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_PATH/build/cmake/android.toolchain.cmake \ -DANDROID_NATIVE_API_LEVEL=21 \ -DANDROID_TOOLCHAIN=clang -DCMAKE_GENERATOR="Ninja" \ -DCMAKE_MAKE_PROGRAM=$ANDROID_SDK_HOME/cmake/$CMAKE_VERSION/bin/ninja \ ../.. $ANDROID_SDK_HOME/cmake/$CMAKE_VERSION/bin/ninja 基本变量解释：ANDROID_ABI：目标ABI，支持armeabi-v7a,arm64-v8a等。ANDROID_NDK：NDK的目录。ANDROID_TOOLCHAIN：编译Cmake使用的工具链，默认clangANDROID_NATIVE_API_LEVEL：编译Android NDK的API级别CMAKE_TOOLCHAIN_FILE：Cmake编译链接时的cmake文件CMAKE_MAKE_PROGRAM：make程序选择Refhttps://www.cnblogs.com/Jeff77/p/14636012.html
获取定位时，Android 11(Q)+ 系统两个权限不能同时申请，否则不弹窗将直接失败，应该第一个授权完成后再请求另一个Manifest.permission.ACCESS_FINE_LOCATION Manifest.permission.ACCESS_BACKGROUND_LOCATION
Android项目工程现在新增了build.gradle.kts文件，可以取代原本的build.gradle文件，一些新的语法也随之更改，以下是设置libs目录（常用于存放.so库)下文件包含的项目：// project/build.gradle.kts plugins { id("com.android.application") version "8.1.2" apply false id("org.jetbrains.kotlin.android") version "1.8.10" apply false id("com.android.library") version "8.1.2" apply false } // .... // app/build.gradle.kts android { compileSdk = 33 defaultConfig { minSdk = 24 multiDexEnabled = true } sourceSets { getByName("main") { jniLibs.srcDirs("libs") } } }
android:lineSpacingMultiplier="1" android:lineSpacingExtra="0pt" android:paddingTop="0pt" android:paddingBottom="0pt" android:includeFontPadding="false"
1. signIn导致弹窗无应用问题复现：该问题在集成HMSCore服务时出现，问题表现为多FA(Multi FA)集成的项目中，在entry模块中调用登录后没有反应，在该Demo测试中，使用的是JS UI模板构建的原子化服务，该Demo需要引用@hms-js-account 库，使用该库进行基本的登录，代码片段如下：signIn: function() { //该登录方式依赖于"@hmscore/hms-jsb-account": "^1.0.300" var scopeList = [OPENID] //表示获取的 var signInOption = new HuaweiIdAuthParamsHelper().setId().setProfile().setScopeList(scopeList).setAuthorizationCode().build(); HuaweiIdAuthManager.getAuthApi().getSignInIntent(signInOption).then((result) = >{ // 登录成功，获取用户的华为帐号信息 console.info("signIn success"); console.info(JSON.stringify(result)); console.info("昵称:" + result.getDisplayName()); console.info("头像:" + result.getAvatarUri()); }). catch((error) = >{ // 登录失败 console.error("signIn fail"); console.error(JSON.stringify(error)); }); } signIn2: function() { //该登录方式依赖于"@hmscore/hms-js-account": "5.2.0-300" HMSAccount.signIn(permissions, scopes).then((res) = >{ //登录成功的处理代码 }). catch((err) = >{ switch (err.resultCode) { //处理异常，2005为网络异常代码 } }); }处理方式：以上问题可以移除非entry模块中metaData闭包中关于com.huawei.hms.client.appid子闭包或者将其自闭包值改为和entry模块中对应的值一样，否则会出现无法登录的问题，该appid由OAuth 2.0生成，此处appid在AppGallery Connect页面中我的应用中可以查看，具体如下："metaData": { "customizeData": [ { //该闭包不应该在非enrty模块内添加 "name": "com.huawei.hms.client.appid", "value": "10xxxxxx" }, { "name": "hwc-theme", "value": "androidhwext:style/Theme.Emui.Translucent.NoTitleBar" } ] }增补：对于使用HMS进行华为账号登录的时候，项目开发的appid可以前往华为开发者联盟凭证中去生成：生成的应用类型选择移动应用，应用包名和SHA256指纹均需要和项目对应。2. 代码修改后调试不生效解决方案：该问题主要是由于IDE工具的缓存问题，建议在不生效的时候先卸载app再安装，同时Rebuild项目，可以使用以下方式进行卸载：$ adb uninstall com.xxx.xxx #需要手机连接上电脑另外一个问题可能是由于跨FA进行调用，这时候调试的时候记得开启Deploy Multi Hap Packages选项。假设项目 hml组件比较多，比如开发人员单独写了一个 NavBarpage组件，如果在其他 Component中（指的是单独一个 Ability）引用，那么缓存的原因就不会更新该Ability引用的hml信息，最终也就在调试的时候看不到预期效果。3. DevEco Studio无法下载SDKNetwork connection failed. Check the network or HTTP proxy settings.该问题主要是由于电脑端的语言设置问题，通过修改以下文件可以纠正：C:\Users\username\AppData\Roaming\Huawei\DevEcoStudio3.1\options\country.region.xml修改成： <countryregion name="CN"/> 再次运行软件即可正常下载SDKs。4. 上架后无法自动下载调用的模块该问题主要是由于原来FA程序的demo中的调用模块Flag缺少自动安装的标记，样例代码如下：Operation operation = new Intent.OperationBuilder() .withDeviceId("") .withBundleName(BUNDLE_NAME) .withAbilityName(PARTIAL_DEVICE_ABILITY_NAME) .withFlags(Intent.FLAG_ABILITY_NEW_MISSION | Intent.FLAG_INSTALL_ON_DEMAND) .build();如果调用的模块为单独的FA模块，那需要添加Intent.FLAG_INSTALL_ON_DEMAND标记才能自动下载对应模块。5. Failure[INSTALL_FAILED_APP_SOURCE_NOT_TRUSTED]该问题主要是由于证书和设备不匹配，在调试的时候我们要确保几点是相对应的：设备的UDID已经添加到列表中使用旧证书的时候需要重新下载*.cer文件（在证书管理页面直接下载对应的证书cer即可）
首次索引项目出现以下错误：Could not resolve all files for configuration ':classpath'.Could not resolve com.android.tools.build:gradle:7.4.1.Required by:....解决方法：将Gradle的JDK改成JDK11（可以使用Android Studio自带的JDK）引用路径：File->Setting->Build,Execution,Deployment->Build Tools-> Gradle
上架帐号：对于上架测试的账号有授权和白名单的要求，如果FA发布到全网且产品未通过发布商用环境，那么普通用户拉起FA后无法显示设备的图片，如果账号在DP平台开启了测试选项，那么可以正常拉起和使用。如果账号没有设置测试选项，那么需要进行以下设置：打开DP平台，用主帐号给该帐号授权，并点击右上角的用户头像->基本资料进行设置，开启智慧生活测试。自测表：FA上架前需要做自测，该自测从华为方获取自测表进行自测。程序包：在DevEco Studio中进行Build App进行导出版本号{ "app": { "bundleName": "com.skyworth.xxx", "vendor": "skyworth", "version": { "code": 1000001, "name": "1.0.1" } } }该闭包展示的是模块的版本号，位于config.json的首个闭包，其中上架后的版本号需要在每个模块中进行单独设置。icon该选项位于config.json上的icon的值，需要进行简单的Logo替换，该logo在正式版可以显示在配网前页面的标识。显示服务名该服务名为展示给用户的服务名，便于辨识原子化服务（针对每个模块均需要进行单独设置）：{ "skills": [ { "entities": [ "entity.system.home" ], "actions": [ "action.system.home" ] } ], "name": "com.skyworth.xxx.MainAbility", "icon": "$media:icon", "description": "该Ability描述", "label": "显示的原子化服务名", "type": "page", "mission": "com.skyworth.xxx", "launchType": "standard" }如下图中的entry_MainAbility则为显示的原子化服务名：软件更新：更新软件包需要重新提测，上传软件包。智慧生活服务以下页面为应用基本信息，需要结合智慧生活服务和上架使用。SHA256证书指纹：该选项需要增加Release证书的SHA256指纹信息，否则无法进行FA授权。包名：对应于Bundle Name。OAuth 2.0客户端ID：该选项对应的是entry模块的config.json的appid选项：{ "metaData": { "customizeData": [ { "name": "com.huawei.hms.client.appid", "value": "OAuth 2.0 Client ID" }, { "name": "hwc-theme", "value": "androidhwext:style/Theme.Emui.Translucent.NoTitleBar" } ] } }Links Ref连接配网内容参考：设备配网-Fi/Combo）-功能开发（Wi-原子化服务-应用开发-HarmonyOS设备开发NFC标签使用参考：生成NFC标签-NFC标签认证-量产管理-HarmonyOS设备开发智慧生活H5开发：文档中心 (harmonyos.com)CodesC++生成码流参考：void convert_hexa(const char *input, char *output) { // 该功能是将字符转换为ASCII码，然后将该码转为16进制 // 如：0 --> 48(十进制) -->30(十六进制) int loop = 0; int i = 0; while (input[loop] != '\0') { sprintf((char *)(output + i), "%02X", input[loop]); loop += 1; i += 2; } // marking the end of the string output[i++] = '\0'; } int Func::GenerateNFC(const char *streamCode, const char *mac, const char *sn, const char *paramEx1, char *result) { // 该功能用于将指定码流模板的MAC生成对应的NFC码流 int len = strlen(mac); char ascii_str[4096] = {0}; // hex string to ascii string convert_hexa(mac, ascii_str); std::string macAscii = std::string(ascii_str); // hex string to int unsigned long long macInt = std::stoull(mac, 0, 16); // operation of mac + 1 unsigned long long macIntPlusOne = macInt + 1; // int to hex string std::stringstream stream; stream << std::hex << macIntPlusOne; std::string resultHex(stream.str()); // padding result to 6 bytes (12 hex number). while (resultHex.size() < 12) { std::string temp = "0"; temp.append(resultHex); resultHex = temp; } // lower case string to upper case std::string resultHexUpperCase = ""; for (auto &token : resultHex) resultHexUpperCase += toupper(token); // 04578BE5219F std::string macPlusOne = resultHexUpperCase; // hex -> hex + 1 std::string split1 = "140C"; // std::string _result = streamCode + macPlusOne + split1 + macAscii + paramEx1; std::string _result = "0347D202426877200100480032374d310081090057200685041417910406" + macPlusOne + "140C" + macAscii + "1701009112" + std::string(mac) + macAscii; strcpy(result, _result.c_str()); return 0; }Java代码参考：// 该类用于存储解析的模板内容，主要分为三部分： // stream: 该串为华为Device Partner申请的码流前段 // paramEx: 该串为170100，目前由华为指定 public class Config { public Config(String stream, String paramEx) { this.stream = stream; this.paramEx = paramEx; } public String stream; public String paramEx; } /* * NEW * 码流模板： * 0332D2022D687720010048003246535200810800552006850414170406A1B2C3D4E5F6140C413142324333443445354636170100 * MAC地址：849DC222FBB2 * 合成目标码流算法： * 0332D2022D68772001004800324653520081080055200685041417 * 0406 * A1B2C3D4E5F6（将0406后面的12位字符替换成MAC地址） * 140C * 413142324333443445354636（将140c后面的24位字符，替换成MAC地址字符串对应的16进制） * 170100 * 输入要求：输入码流模板，输入目标MAC地址 * 输出要求：输出目标码流 */ public Config parseTemplate(String steamCodeTemplate) { int found = steamCodeTemplate.indexOf("0406"); int MAC_LENGTH = 12; String subStreamStr = steamCodeTemplate.substring(0, found + 4); // stream+0406 String subLastStr = steamCodeTemplate.substring(found + 4 + MAC_LENGTH + 4 + 2 * MAC_LENGTH); return new Config(steamCodeTemplate.substring(0, found), subLastStr); } public static String genNFCCodeForOHOS(String stream, String paramEX, String mac) { StringBuilder macPlusOne = new StringBuilder(Long.toHexString(Long.parseLong(mac, 16) + 1)); while (macPlusOne.length() < 12) { macPlusOne.insert(0, "0"); } String newResult = stream + "0406" + macPlusOne + "140C" + HEXUtil.asciiChar2HexValue(mac) + paramEX; return newResult.toUpperCase(); } // genNFCCodeC++程序样例ht_toolkit_nfc.exeht_toolkit_nfc.exe)
简述在前面我们已经阐述过了关于鸿蒙以及开源鸿蒙的基本信息，以用于理清它们之前的基本关系，现在我们就开始进行基本的开发吧。预备内容华为开发者联盟官网DevEco Studio 3.0 Beta 1准备工作下载开发工具DevEco Studio 3.0 Beta 1通过DevEco的SDK Manager进行下载SDK(顶部菜单)Tools->OpenHarmony SDK->SDK Manager将OpenHarmony SDK和HarmoyOS Legacy SDK的全部API版本进行下载（主要是为了支持一些老旧的设施。新建项目在此处我们选择Empty Ability选择后我们先使用简单Js语言开发，后续高级功能将会联动Java UI进行开发。在这个界面中，黄色标框的内容值得简述一下，对于Atomic Service 以及 Application ，两者的区别是是否生成App Logo（非快捷方式），两者均可选择，主要是前者需要进入我的服务（屏幕滑动左下角或者右下角进入) 进入常用的卡片才能看到该应用，后者则是普通App方式。在此处选用的是Application模式，其中Bundle Name是指识别该应用的一个包名，后续设置签名等都需要与之对应。等项目Gradle同步完成后进行调试的签名通过DevEco创建一个keystore，包含.p12,.csr两个文件创建*.p12文件如果没有则需要选择New剩下的可以按照key的要求进行填写，此处仅作为调试测试，所以此处的CERT信息只填写第一个First and last Name针对于CSR生成，类似于keystore的选择，填写好路径后完成即可生成你需要的keystore以及csr文件。创建好所需的.p12以及.csr后，则需要进行*.crt文件的创建创建CRT文件需要进入AppGallery官网该页面由华为开发者联盟处进入进入该官网先进行自行注册，进入首页中我的项目然后 添加项目，创建好项目后需要进行添加应用下载完后接着下载agconnect-services.json并将其复制到项目工程的entry模块中去，并按照推荐的配置步骤进行配置，比如设置build.gradle文件的依赖。在此处我们选择App(HarmonyOS)，因为我们此次针对的是HarmonyOS开发，诸如此类选择后续不再另行提醒。注：此处设定的包名和开发的应用的entry中的bundleName需要一致。配置证书设置好以上步骤后，我们需要设置调试证书用于真机调试，在下图中选择用户与访问并进入左侧栏的证书管理中进行管理。由以上步骤生成myapp-dev.cer文件后，下载到和myapp-dev.p12等文件同一个目录，方便后续进行配置。配置证书过程中，我们还差一个.p7b文件需要下载，该文件依赖于测试真机，这时候我们连接上华为鸿蒙系统的手机，此处我将使用Mate40进行调试。以下我们进行设备管理，该路径位于证书管理下，添加设备前需要获取UDID：> adb shell bm get -udid获取后复制到UDID栏目中并提交登记。最后回到项目中应用的HAP Provision Profile进行p7b文件下载生成.p7b文件后下载到证书同目录，方便进行后续配置。如果需要进行HMS服务开发，还需要添加myapp-dev.p12导出的SHA256指纹信息：$ keytool -list -v -keystore myapp-dev.p12正式开发此时我们配置好了基本的签名、设备等信息，这时候我们回到项目工程的Project Structure中配置项目的签名文件：最后运行：
Alert/Popup Windowhttps://foso.github.io/Jetpack-Compose-Playground/material/alertdialog/https://rrtutors.com/tutorials/How-to-create-overflow-menu-in-Jetpack-composeJetpack Compose DropMenuvar expanded by remember { mutableStateOf(false) } DropdownMenu( expanded = expanded, onDismissRequest = { expanded = false } ) { DropdownMenuItem(onClick = { /* Handle refresh! */ }) { Text("Refresh") } DropdownMenuItem(onClick = { /* Handle settings! */ }) { Text("Settings") } Divider() DropdownMenuItem(onClick = { /* Handle send feedback! */ }) { Text("Send Feedback") }