于Use MusicBrainz in iOS之后,因为MusicBrainz找出专辑封面,它只能转移到其他网站提供的音乐信息搜索服务,领导给出GraceNote。(有压力。。

。)

需求类似:通过一个音频文件的歌曲名,专辑名等信息查询到该文件专辑的封面。

本文介绍下怎样在iOS中使用GraceNote给出的GNSDK(一个用C写的SDK)。并通过序列化的GDO查询专辑封面。实际上,就是我对GNSDK文件里给出的samples的一些修正和调用而已。

首先前往GraceNote站点注冊一个帐号。然后创建一个app(看得懂英语的都知道怎么做吧,我就略过了),完毕后例如以下所看到的:

新建一个Demoproject。名字和上面的app名一致(不一致是否可行,我还没试过)。

下载GNSDK:点击打开链接

本文基于3.0.6版本号。

下载完毕后解压。前往lib_static/ios_armv7s-32。因为我的机子指令集是armv7s。所以使用该目录中的静态库文件。将全部.a文件拷贝到Demoproject中。

再将include文件夹下的全部.h文件和ios_armv7s_32文件夹拷贝到Demoproject中。

完毕后project文件夹例如以下:

打开Build Settings选项。设置Header Search Paths和Library Search Paths:

确保Build Phases所有静态库链接成功:

在project中新建一个文本文件,比如my_licence.txt,内容为你所创建的App Details中的License String中的内容(注意不要有不论什么修改,空缺的信息无需补上),示比例如以下:

-- BEGIN LICENSE v1.0 1CBA6766 --
licensee: Gracenote, Inc.
name:
notes: Lic Gen 2.1
start_date: 0000-00-00
client_id: 4541440
musicid_file: enabled
musicid_search: enabled
musicid_stream: enabled
musicid: enabled
playlist: enabled
-- SIGNATURE 1CBA6766 --
lAADAgAe5/qrtIoNKp6SWqcqU+a+R6l/SaJ3aW5YQ+93T7nPAB8Bm9BtwE5OsPgoKjHK14foIdX5dPugbz1mJnkfT6Kt
-- END LICENSE 1CBA6766 --

新建一个Test.C,代码例如以下:

#define USE_LOCAL                   0#define GNSDK_LINK                  1
#define GNSDK_STORAGE_SQLITE        1
#include "gnsdk.h"gnsdk_byte_t* response_data;
gnsdk_size_t response_data_length;#include <stdio.h>
#include <string.h>
#include <stdlib.h>/***********************************************   Local Function Declarations**********************************************/static int
_init_gnsdk(const char*          client_id,const char*          client_id_tag,const char*          client_app_version,const char*          license_path,gnsdk_user_handle_t* p_user_handle);static void
_shutdown_gnsdk (gnsdk_user_handle_t user_handle);static void
_query_for_album_images (gnsdk_user_handle_t user_handle);/******************************************************************** MAIN*******************************************************************/
int
coverart_main(int argc, const char* argv[])
{gnsdk_user_handle_t user_handle        = GNSDK_NULL;const char*         client_id          = NULL;const char*         client_id_tag      = NULL;const char*         client_app_version = "1";      /* increment with each version of your app */const char*         license_path       = NULL;int                 rc                 = 0;/* Client ID, Client ID Tag and License file must be passed in */if (argc == 4){client_id     = argv[1];client_id_tag = argv[2];license_path  = argv[3];/* Initialize GNSDK   */rc = _init_gnsdk(client_id,client_id_tag,client_app_version,license_path,&user_handle);if (0 == rc){/* Perform a sample cover art query */_query_for_album_images(user_handle);/* Clean up and shutdown */_shutdown_gnsdk(user_handle);}}else{printf("\nUsage:\n%s clientid clientidtag license\n", argv[0]);rc = -1;}return rc;}   /* main() *//********************************************************************    _DISPLAY_LAST_ERROR**    Echo the error and information.******************************************************************/
static void
_display_last_error(int line_num)
{/* Get the last error information from the SDK */const gnsdk_error_info_t* error_info = gnsdk_manager_error_info();/* Error_info will never be GNSDK_NULL.* The SDK will always return a pointer to a populated error info structure.*/printf("\nerror from: %s()  [on line %d]\n\t0x%08x %s",error_info->error_api,line_num,error_info->error_code,error_info->error_description);} /* display_last_error() *//********************************************************************   _GET_USER_HANDLE**    Load existing user handle, or register new one.**    GNSDK requires a user handle instance to perform queries.*    User handles encapsulate your Gracenote provided Client ID which is unique for your*    application. User handles are registered once with Gracenote then must be saved by*    your application and reused on future invocations.******************************************************************/
static int
_get_user_handle(const char*          client_id,const char*          client_id_tag,const char*          client_app_version,gnsdk_user_handle_t* p_user_handle)
{gnsdk_user_handle_t user_handle       = GNSDK_NULL;gnsdk_str_t         serialized_user   = GNSDK_NULL;gnsdk_error_t       error             = GNSDK_SUCCESS;char*               user_filename     = NULL;size_t              user_filename_len = 0;int                 rc                = 0;FILE*               file              = NULL;//    user_filename_len = strlen(client_id)+strlen("_user.txt")+1;
//  user_filename     = malloc(user_filename_len);user_filename_len = strlen("/var/mobile/Applications/1B3B6648-8D50-430F-B7D2-21D99AA78B6F/tmp/4541440_user.txt") + 1;user_filename = malloc(user_filename_len);if (NULL != user_filename){
//      strcpy(user_filename, client_id);
//      strcat(user_filename, "_user.txt");strcpy(user_filename, "/var/mobile/Applications/1B3B6648-8D50-430F-B7D2-21D99AA78B6F/tmp/4541440_user.txt");//       /* Do we have a user saved locally? */
//      file = fopen(user_filename, "r");
//      if (NULL != file)
//      {
//          gnsdk_char_t serialized_user_string[1024] = {0};
//
//          if (NULL != (fgets(serialized_user_string, 1024, file)))
//          {
//              /* Create the user handle from the saved user */
//              error = gnsdk_manager_user_create(serialized_user_string, client_id, client_id_tag, client_app_version, &user_handle);
//              if (GNSDK_SUCCESS != error)
//              {
//                  _display_last_error(__LINE__);
//                  rc = -1;
//              }
//          }
//          else
//          {
//              printf("Error reading user file into buffer.\n");
//              rc = -1;
//          }
//          fclose(file);
//      }
//      else
//      {
//          printf("\nInfo: No stored user - this must be the app's first run.\n");
//      }/* If not, create new one*/if (GNSDK_NULL == user_handle){error = gnsdk_manager_user_register(GNSDK_USER_REGISTER_MODE_ONLINE, client_id, client_id_tag, client_app_version, &serialized_user);if (GNSDK_SUCCESS != error){_display_last_error(__LINE__);rc = -1;}else{/* save newly registered user for use next time */file = fopen(user_filename, "w");if (NULL != file){if (0 > fputs(serialized_user, file)){printf("Error writing user registration file from buffer.\n");rc = -1;}fclose(file);}else{printf("\nError: Failed to open the user filename for use in saving the updated serialized user. (%s)\n", user_filename);}/* Create the user handle from the registered user */error = gnsdk_manager_user_create(serialized_user, client_id, client_id_tag, client_app_version, &user_handle);if (GNSDK_SUCCESS != error){_display_last_error(__LINE__);rc = -1;}gnsdk_manager_string_free(serialized_user);}}free(user_filename);}else{printf("Error allocating memory.\n");rc = -1;}if (rc == 0){*p_user_handle = user_handle;}return rc;
} /* _get_user_handle() *//******************************************************************** _ENABLE_LOGGING**  Enable logging for the SDK. Not used by Sample App. This helps*  Gracenote debug your app, if necessary.*******************************************************************/
static int
_enable_logging(void)
{gnsdk_error_t error = GNSDK_SUCCESS;int           rc    = 0;error = gnsdk_manager_logging_enable("/var/mobile/Applications/1B3B6648-8D50-430F-B7D2-21D99AA78B6F/tmp/sample.log",                                           /* Log file path */GNSDK_LOG_PKG_ALL,                                      /* Include entries for all packages and subsystems */GNSDK_LOG_LEVEL_ERROR|GNSDK_LOG_LEVEL_WARNING,          /* Include only error and warning entries */GNSDK_LOG_OPTION_ALL,                                   /* All logging options: timestamps, thread IDs, etc */0,                                                      /* Max size of log: 0 means a new log file will be created each run */GNSDK_FALSE                                             /* GNSDK_TRUE = old logs will be renamed and saved */);if (GNSDK_SUCCESS != error){_display_last_error(__LINE__);rc = -1;}return rc;} /* _enable_logging() *//** Set the application Locale.*/
static int
_set_locale (gnsdk_user_handle_t user_handle)
{gnsdk_locale_handle_t locale_handle = GNSDK_NULL;gnsdk_error_t         error         = GNSDK_SUCCESS;int                   rc            = 0;error = gnsdk_manager_locale_load(GNSDK_LOCALE_GROUP_MUSIC,               /* Locale group */GNSDK_LANG_ENGLISH,                     /* Languae */GNSDK_REGION_DEFAULT,                   /* Region */GNSDK_DESCRIPTOR_SIMPLIFIED,                /* Descriptor */user_handle,                            /* User handle */GNSDK_NULL,                             /* User callback function */0,                                      /* Optional data for user callback function */&locale_handle                          /* Return handle */);if (GNSDK_SUCCESS == error){/* Setting the 'locale' as default* If default not set, no locale-specific results would be available*/error = gnsdk_manager_locale_set_group_default(locale_handle);if (GNSDK_SUCCESS != error){_display_last_error(__LINE__);rc = -1;}/* The manager will hold onto the locale when set as default* so it's ok to release our reference to it here*/gnsdk_manager_locale_release(locale_handle);}else{_display_last_error(__LINE__);rc = -1;}return rc;} /* _set_locale() *//******************************************************************** _INIT_GNSDK**     Initializing the GNSDK is required before any other APIs can be called.*     First step is to always initialize the Manager module, then use the returned*     handle to initialize any modules to be used by the application.**     For this sample, we also load a locale which is used by GNSDK to provide*     appropriate locale-sensitive metadata for certain metadata values. Loading of the*     locale is done here for sample convenience but can be done at anytime in your*     application.******************************************************************/
static int
_init_gnsdk(const char*          client_id,const char*          client_id_tag,const char*          client_app_version,const char*          license_path,gnsdk_user_handle_t* p_user_handle)
{gnsdk_manager_handle_t sdkmgr_handle = GNSDK_NULL;gnsdk_error_t          error         = GNSDK_SUCCESS;gnsdk_user_handle_t    user_handle   = GNSDK_NULL;int                    rc            = 0;/* Initialize the GNSDK Manager */error = gnsdk_manager_initialize(&sdkmgr_handle,license_path,GNSDK_MANAGER_LICENSEDATA_FILENAME);if (GNSDK_SUCCESS != error) { _display_last_error(__LINE__); return -1; }/* Enable logging */if (0 == rc)rc = _enable_logging();/* Initialize the Storage SQLite Library */if (0 == rc){error = gnsdk_storage_sqlite_initialize(sdkmgr_handle);if (GNSDK_SUCCESS != error) { _display_last_error(__LINE__); rc = -1; }}/* For this library to successfully operate, you must first establish a valid storage folder path using the* GNSDK_SQLITE_OPTION_STORAGE_FOLDER option. */error = gnsdk_storage_sqlite_option_set(GNSDK_STORAGE_SQLITE_OPTION_STORAGE_FOLDER,   // option name : storage folder [required]"/var/mobile/Applications/1B3B6648-8D50-430F-B7D2-21D99AA78B6F/Documents"                                           // option value : "." set it to current directory for this sample);if( GNSDK_SUCCESS != error){_display_last_error(__LINE__);return -1;}error = gnsdk_manager_storage_location_set(GNSDK_MANAGER_STORAGE_QUERYCACHE, "/var/mobile/Applications/1B3B6648-8D50-430F-B7D2-21D99AA78B6F/Documents/querycache");if (GNSDK_SUCCESS != error){_display_last_error(__LINE__);}/* Initialize the Link Content Library */if (0 == rc){error = gnsdk_link_initialize(sdkmgr_handle);if (GNSDK_SUCCESS != error) { _display_last_error(__LINE__); rc = -1; }}/* Get a user handle for our client ID.  This will be passed in for all queries */if (0 == rc){rc = _get_user_handle(client_id,client_id_tag,client_app_version,&user_handle);}/* Set the 'locale' to return locale-specifc results values. This examples loads an English locale. */if (0 == rc)rc = _set_locale(user_handle);if (0 != rc){/* Clean up on failure. */_shutdown_gnsdk(user_handle);}else{/* return the User handle for use at query time */*p_user_handle = user_handle;}return rc;}   /* _init_gnsdk() *//********************************************************************  _SHUTDOWN_GNSDK**     Call shutdown all initialized GNSDK modules.*     Release all existing handles before shutting down any of the modules.*     Shutting down the Manager module should occur last, but the shutdown ordering of*     all other modules does not matter.******************************************************************/
static void
_shutdown_gnsdk (gnsdk_user_handle_t user_handle)
{gnsdk_error_t error                          = GNSDK_SUCCESS;error = gnsdk_manager_user_release(user_handle);if (GNSDK_SUCCESS != error){_display_last_error(__LINE__);}/* Shutdown the Manager to shutdown all libraries */gnsdk_manager_shutdown();
}/*-----------------------------------------------------------------------------*  _fetch_image*/
static int
_fetch_image(gnsdk_link_query_handle_t query_handle,gnsdk_link_content_type_t image_type,gnsdk_char_t*             image_type_str)
{gnsdk_link_data_type_t data_type   = gnsdk_link_data_unknown;gnsdk_byte_t*          buffer      = GNSDK_NULL;gnsdk_size_t           buffer_size = 0;int                    rc          = 0;gnsdk_error_t          error       = GNSDK_SUCCESS;error = gnsdk_link_query_content_retrieve(query_handle,image_type,1,&data_type,&buffer,&buffer_size);if (GNSDK_SUCCESS == error){/* data_type will always be == gnsdk_link_data_image_jpeg *//* Do something with the image, e.g. display, save, etc. Here we just print the size. */printf("\nRETRIEVED: %s image: %d byte JPEG\n", image_type_str, (gnsdk_uint32_t)buffer_size);response_data = buffer;response_data_length = buffer_size;//        for (int i = 0; i < buffer_size; i++) {
//            printf("%x", *(buffer + i));
//        }/* free the data when you are done with it */error = gnsdk_link_query_content_free(buffer);if (GNSDK_SUCCESS != error){_display_last_error(__LINE__);rc = -1;}}else{if (GNSDKERR_NotFound != GNSDKERR_ERROR_CODE(error)){_display_last_error(__LINE__);rc = -1;}else{/* Do not return error code for not found. *//* For image to be fetched, it must exist in the size specified and you must be entitled to fetch images. */printf("\nNOT FOUND: %s image\n", image_type_str);}}return rc;
}/*-----------------------------------------------------------------------------*  _query_for_album_images*/
static void
_query_for_album_images (gnsdk_user_handle_t user_handle)
{gnsdk_gdo_handle_t        input_gdo            = GNSDK_NULL;gnsdk_link_query_handle_t query_handle         = GNSDK_NULL;gnsdk_cstr_t              image_size           = GNSDK_NULL;gnsdk_cstr_t              preferred_image_size = GNSDK_NULL;gnsdk_error_t             error                = GNSDK_SUCCESS;printf("\n*****Sample Link Album Query*****\n");/* Create the query handle. Do not include a callback or callback data (2nd & 3rd args are GNSDK_NULL). */error = gnsdk_link_query_create(user_handle, GNSDK_NULL, GNSDK_NULL, &query_handle);if (GNSDK_SUCCESS != error) { _display_last_error(__LINE__); return; }/* Set the input GDO */if (GNSDK_SUCCESS == error){gnsdk_cstr_t serialized_gdo = "WEcxAbwX1+DYDXSI3nZZ/L9ntBr8EhRjYAYzNEwlFNYCWkbGGLvyitwgmBccgJtgIM/dkcbDgrOqBMIQJZMmvysjCkx10ppXc68ZcgU0SgLelyjfo1Tt7Ix/cn32BvcbeuPkAk0WwwReVdcSLuO8cYxAGcGQrEE+4s2H75HwxFG28r/yb2QX71pR";/* Typically, the GDO passed in to a Link query will come from the output of a GNSDK query.* For an example of how to perform a query and get a GDO please refer to the documentation* or other sample applications.* The below serialized GDO was an 1-track album result from another GNSDK query.*/error = gnsdk_manager_gdo_deserialize(serialized_gdo, &input_gdo);if (GNSDK_SUCCESS == error){error = gnsdk_link_query_set_gdo(query_handle, input_gdo);if (GNSDK_SUCCESS != error) { _display_last_error(__LINE__); }gnsdk_manager_gdo_release(input_gdo);}else{_display_last_error(__LINE__);}}/* Set preferred image size */preferred_image_size = GNSDK_LINK_OPTION_VALUE_IMAGE_SIZE_170;/* Obtain image size available */image_size = preferred_image_size;/* Specify the desired image size */if (GNSDK_SUCCESS == error){if (GNSDK_NULL != image_size){error = gnsdk_link_query_option_set(query_handle,GNSDK_LINK_OPTION_KEY_IMAGE_SIZE,image_size);if (GNSDK_SUCCESS != error){_display_last_error(__LINE__);}else{/* Perform the image fetches */_fetch_image(query_handle, gnsdk_link_content_cover_art, "cover art");
//              _fetch_image(query_handle, gnsdk_link_content_image_artist, "artist");}}}/* release the Link query handle */gnsdk_link_query_release(query_handle);} /* _query_for_album_images() */

注意。为了便利(个人也很的懒惰),代码中关于路径的代码直接使用了硬编码。比如:

"/var/mobile/Applications/1B3B6648-8D50-430F-B7D2-21D99AA78B6F/Documents/querycache"。

再写个Test.h开放接口出来:

#ifndef GNTest_iOS_Test_h
#define GNTest_iOS_Test_hint coverart_main(int argc, const char* argv[]);#endif

最后回到一个普通的ViewController文件里,代码例如以下:

#import "ViewController.h"
#import "Test.h"
#import "ShareData.h"
#include "gnsdk.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad
{[super viewDidLoad];NSString *licencePath = [[NSBundle mainBundle] pathForResource:@"my_licence" ofType:@"txt"];const char* pathPtr = [licencePath UTF8String];const char* argv[] = {NULL, "4541440", "79EFBF4E21724D084BA87FF9B242F0C9", pathPtr};NSLog(@"%@", licencePath);coverart_main(4, argv);extern gnsdk_byte_t* response_data;extern gnsdk_size_t response_data_length;NSData *data = [NSData dataWithBytes:response_data length:response_data_length];NSLog(@"%@", data);UIImage *image = [UIImage imageWithData:data];[self.album_imageView setImage:image];
}@end

简单说下其执行过程,在sample中有一个所谓的序列化GDO(GraceNote Data Objects,是该站点自定的一种数据模型),该GDO由一列字符串标识,它相应的音乐专辑就是我们的查询目标。

gnsdk_cstr_t serialized_gdo = "WEcxAbwX1+DYDXSI3nZZ/L9ntBr8EhRjYAYzNEwlFNYCWkbGGLvyitwgmBccgJtgIM/dkcbDgrOqBMIQJZMmvysjCkx10ppXc68ZcgU0SgLelyjfo1Tt7Ix/cn32BvcbeuPkAk0WwwReVdcSLuO8cYxAGcGQrEE+4s2H75HwxFG28r/yb2QX71pR";

然后调用查询接口(就是C文件里的“主函数”):

    const char* pathPtr = [licencePath UTF8String];const char* argv[] = {NULL, "4541440", "79EFBF4E21724D084BA87FF9B242F0C9", pathPtr};NSLog(@"%@", licencePath);coverart_main(4, argv);

当中argv[]中的第二个參数是App Details中的client id,第三个參数是App Details中的client tag,第四个參数是上面的my_licence.txt文件的路径。

在查询完毕后,站点返回的二进制数据保存在一个缓冲区中,我将其起始位置和缓冲区长度保存在下面全局变量中:

gnsdk_byte_t* response_data;
gnsdk_size_t response_data_length;

最后解析缓冲区中的数据。并以UIImage形式展示出来:

    extern gnsdk_byte_t* response_data;extern gnsdk_size_t response_data_length;NSData *data = [NSData dataWithBytes:response_data length:response_data_length];NSLog(@"%@", data);UIImage *image = [UIImage imageWithData:data];[self.album_imageView setImage:image];

接着我又偷了懒。打开PP助手,在app的Documents文件夹下创建一个querycache文件夹(用于存储查询结果到本地缓存中。这一步不可缺少):

在armv7s 32位机子上的执行。

控制台部分输出例如以下:

2014-04-25 22:43:55.906 GNTest_iOS[784:60b] /var/mobile/Applications/1B3B6648-8D50-430F-B7D2-21D99AA78B6F/GNTest_iOS.app/my_licence.txt*****Sample Link Album Query*****RETRIEVED: cover art image: 11808 byte JPEG
2014-04-25 22:43:58.470 GNTest_iOS[784:60b] <ffd8ffe0 00104a46 49460001 01010060 00600000 ffdb0043 00080606 07060508 07070709 09080a0c 140d0c0b 0b0c1912 130f141d 1a1f1e1d 1a1c1c20 242e2720 222c231c 1c283729 2c303134 34341f27 393d3832 3c2e3334 32ffdb00 43010909 090c0b0c 180d0d18 32211c21 32323232 32323232 32323232 32323232 32323232 32323232 32323232 32323232 32323232 32323232 32323232 32323232 3232ffc0 00110800 aa00aa03 01220002 11010311 01ffc400 1f000001 05010101 01010100 00000000 00000001 02030405 06070809 0a0bffc4 00b51000 02010303 02040305 05040400 00017d01

执行结果例如以下,也就是上面的GDO相应的专辑封面图片:

本文比較乱,Demo中的代码还有非常多地方要改善。等后面将关键的技术问题解决后再写篇博客好好梳理下,到时候我会给出无需不论什么手工操作的Demo。

版权声明:本文博主原创文章。博客,未经同意不得转载。

转载于:https://www.cnblogs.com/hrhguanli/p/4867634.html

Use GraceNote SDK in iOS(一)通过序列化GDO查询专辑封面相关推荐

  1. Use GraceNote SDK in iOS(一)通过序列化的GDO查询专辑封面

    在Use MusicBrainz in iOS之后,由于MusicBrainz查不到专辑封面,只能转移到其它提供音乐信息搜索服务的网站,领导给出的就是GraceNote.(有压力...) 需求类似:通 ...

  2. Use GraceNote SDK in iOS(二)获取音乐的完整信息

    在需求彻底明朗化,外加从MusicFans转到GraceNote,再从GraceNote的GNSDK转到iOS SDK后,最终完毕了在iOS上通过音乐的部分信息获取完整信息的功能了.(好吧,我承认是相 ...

  3. IOS 归档 即序列化与反序列化

    IOS 归档 即序列化与反序列化 小弟很久没有更新了 最近在往IOS上靠 IOS中的归档  即是我们所知道的序列化和反序列化 我们可以用plist来存储比较简单的数据类型 但是如果我想把自己定义的类型 ...

  4. 中国移动灵犀云语音识别及合成SDK(iOS)使用指南

    随着智能家居概念的火热,语音交互这一新时代的人机交互方式再度掀起了热潮.移动互联网应用在设计开发时也纷纷考虑加入语音识别功能,带给用户除传统键盘或触控交互方式外的更便捷交互体验.中国移动近日推出的&q ...

  5. untiy接入微信SDK实现iOS分享

    untiy接入微信SDK实现iOS分享功能 说明: 使用平台:mac电脑 Unity处理 进入微信开发者官网申请应用 2.下载微信的开发工具包sdk导入untiy的 Assest/Plugins/iO ...

  6. Cognex Mobile Barcode SDK for iOS

    概述 Cognex Mobile Barcode SDK (cmbSDK) 是用于开发移动条码扫描应用程序的SDK. SDK是付费的,但功能很强大. Cognex Mobile Barcode SDK ...

  7. 基于声网 SDK 实现 iOS 端的一对一视频通话

    在很多产品,加入实时视频通话已经不是新鲜事情了,尤其是近几年的疫情影响,个人公司国家对于实时音视频的需求一直在快速的增长.例如视频会议.社交应用.实时游戏,甚至也可能出现在一些元宇宙的场景中. 本文将 ...

  8. ArcGIS Runtime SDK for iOS之符号和渲染

    本篇文章翻译自与点击打开链接,有不妥之处还请大家多多指正! 符号定义了图形外观的非地理方面.它包括了图形的颜色.线宽.透明度等等.ArcGIS Runtime SDK for iOS包含了许多符号类, ...

  9. uniapp离线打包升级SDK(iOS端)

    uniapp离线打包升级SDK(iOS端) 使用的工具 苹果账号 生成CertificateSigningRequest.certSigningRequest文件 创建Certificates 创建p ...

最新文章

  1. 邮件回复功能失效 谁遇到过?
  2. OpenCVSharp_保存浮点型Mat数据
  3. python真的好吗-python的缩进格式真的不好吗?
  4. OpenCV进口重建Import Reconstruction
  5. 关于C++/C中符号
  6. CentOS 7 安装 JDK
  7. 随想录(为什么循环队列具有先天的并行性)
  8. c/c++入门教程 - 1.基础c/c++ - 1.0 Visual Studio 2019安装环境搭建
  9. opencv之CmakeLists.txt配置
  10. Make things beautiful again !
  11. 【EOS】2.2 发行Token,转移Token
  12. 0712CF解题报告
  13. c语言小游戏编程弹珠游戏,C/C++知识点之c语言 弹弹球小游戏
  14. Java、JSP新华书店网上售书系统
  15. 矩阵基变换和坐标变换
  16. python--实现汇率转换
  17. 《实战java程序设计---上》
  18. Word随手记:关于Word中大括号内的多行公式对齐问题
  19. Java多线程_并发协助模型(管制法,信号灯法)
  20. Android-简单单词书app

热门文章

  1. led投影仪能换大功率灯吗_投影机改装成led灯的方法是什么?
  2. openfeign异常--NoSuchBeanDefinitionException: No qualifying bean of type
  3. 分布式框架(一):分布式协议
  4. scss flex布局
  5. Android 安装apk时,报错 Failure [INSTALL_FAILED_TEST_ONLY]
  6. 开源项目 rails4scm 软件配置管理
  7. JVM学习笔记(九)———Shenandoah垃圾收集器
  8. 软件测试的职业生涯历程
  9. 【VBA研究】用XMLHTTP的Post功能抓取数据
  10. 林清轩官宣全新品牌代言人杨祐宁