Use GraceNote SDK in iOS(一)通过序列化GDO查询专辑封面
于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_h int 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。
版权声明:本文博主原创文章。博客,未经同意不得转载。
Use GraceNote SDK in iOS(一)通过序列化GDO查询专辑封面的更多相关文章
- Use GraceNote SDK in iOS(二)获取音乐的完整信息
在需求彻底明朗化,外加从MusicFans转到GraceNote,再从GraceNote的GNSDK转到iOS SDK后,最终完毕了在iOS上通过音乐的部分信息获取完整信息的功能了.(好吧,我承认是相 ...
- 移动端影像解决方案Adobe Creative SDK for ios
移动端影像解决方案Adobe Creative SDK for ios 2015-12-20 分类:整理 阅读(390) 评论(0) 老牌影像界泰斗不甘落寞,正式推出了Adobe Creative ...
- ArcGIS Runtime SDK for iOS开发地图图层-图形图层
注:本文翻译自:https://developers.arcgis.com/ios/objective-c/guide/creating-a-graphics-layer.htm 创建图 ...
- ArcGIS Runtime SDK for iOS之符号和渲染
符号定义了图形外观的非地理方面.它包括了图形的颜色.线宽.透明度等等.ArcGIS Runtime SDK for iOS包含了许多符号类,其中的每个类可以让你以独特的方式指定符号.每个符号的类型也是 ...
- FFmpeg SDK for iOS
FFmpeg是一套可以用来记录.转换数字音频.视频,并能将其转化为流的跨平台开源计算机程序. 很多平台视频播放器都是使用FFmpeg来开发的,FFmpeg官方并没有为各个平台提供编译好的SDK,所以使 ...
- [BEROR]CodeSign error: code signing is required for product type 'Application' in SDK 'iOS 8.1'
解决方法: 选择project->Build Settings -> Code Signing -> Code Signing Identity -> Debug -> ...
- 视频直播SDK-ios版
IOS视频直播接入说明 一.名词解释 分辨率:用于计算机视频处理的图像,以水平和垂直方向上所能显示的像素数来表示分辨率.常见视频分辨率的有1080P即1920x1080,720P即1080x720,6 ...
- 探寻不同版本号的SDK对iOS程序的影响
PDF版本号:http://pan.baidu.com/s/1eQ8DVdo 结论: 同样的代码.使用不同版本号的SDK来编译.会影响MachO头中的值, 从而使程序表现出不同的外观. 代码: - ( ...
- ArcGIS Runtime SDK for iOS开发系列教程(5)——要素信息的绘制
在客户端绘制点.线.面要素是GIS应用的基本功能,这一讲我将向大家介绍在iOS中如何来实现这一功能.大家都知道在Flex.Silverlight.js中对于要素的绘制都有一个叫GraphicsLaye ...
随机推荐
- SVN版本日志对话框命令使用指南
日志使用指南 http://tortoisesvn.net/docs/nightly/TortoiseSVN_zh_CN/tsvn-dug-showlog.html
- 第一个androidAPP项目总结—数据请求
1.使用 ShenBuLuoHttpImpl.getMHttpImpl(context).getAddressList(mod.getCouponCode(), new HttpAfter() { @ ...
- Windows计划任务 未能启动
近期在windows server 2003上运行的备份脚本,在7月23日之后,没再运行,在计划任务里看到的状态是:未能启动.结果手动运行了一下备份脚本,没有问题,可以正常运行,但是在计划任务里为什么 ...
- Php RSS
RSS 聚合最近非常流行,因此至少对 RSS 及其工作方式有所了解是一名 PHP 开发人员的迫切需要.本文介绍了 RSS 基础知识.RSS 众多用途中的一些用途.如何使用 PHP 从数据库创建 RSS ...
- uva 10154 贪心+dp
题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem ...
- Rational Rose 7.0的使用(转)
1.Rose如何隐藏类的属性和操作? 右击类图,选择Options->Suppress Attributes/Suppress Operations 2.Rose中如何表示双向关联? 右击关联线 ...
- GitHub——如何更新已经fork的代码
github上有个很方便的功能叫fork,将别人的工程一键复制到自己账号下.这个功能很方便,但有点不足的是,当源项目更新后,你fork的分支并不会一起更新,需要自己手动去更新.下面记录下网上找到的更新 ...
- LR:Code - 60990,Code - 10343 问题解决
Code - 60990 Error: Two Way Communication Error: Function two_way_comm_post_message /two_way_comm_po ...
- 正则表达式中/g的含义
关于正则表达式 g,m 参数的总结,为了回答“正则表达式(/[^0-9]/g,'')中的"/g"是什么意思?” 为了解答“正则表达式(/[^0-9]/g,'')中的" ...
- jquery创始人
http://developer.51cto.com/art/201102/244898.htm jQuery由美国人John Resig创建,至今已吸引了来自世界各地的众多javascript高手加 ...