项目开发笔记 (七)

很多APP中都会有个人信息,或者个人帐号 都会有设置头像功能,国内的很多APP更加是如此(很多人的帐号密码泄密,正是由于到处注册帐号,举个我当年密码泄漏的例子,在很多年的某一天 我在某个网吧的嘟嘟牛系统注册了一个帐号,当时毫无安全意识,直接用个人密码作为嘟嘟牛的密码,很多年后的今天 我在嘟嘟牛的用户数据库里找到了我当年的个人所有信息…嘟嘟牛的数据库怎么会流出来?A.黑客把嘟嘟牛黑掉,把数据库拿到地下交易市场卖,B.嘟嘟牛的某个数据库程序员离职 顺带把数据库带出来,C.公司倒闭,倒卖数据榨干最后一点价值等等..),言归正传,目前我在参与一个类APP项目的优化工作.使用Unity开发.也有这种..设置用户头像的需求

Unity Version: 5.x or 4.x

本文内容非纯干货,如果不想看可以直接下载Sample – 传送门

难点主要在几个地方:

  1. Unity与iOS/Android原生代码之间的调用
  2. iOS/Android 对摄像机的调用与图片截取
  3. iOS/Android 对图片的IO操作
  4. 上传图片

Unity与iOS/Android原生代码之间的调用

Unity对原生的调用支持相对还是很好的.也非常简单.

  • 对于Android

主要的方法是通过获取主Activity对象,然后调用主Activity中的pubilc信息,举个栗子

AndroidJavaClass androidActivityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
m_NativeObj = androidActivityClass.GetStatic("currentActivity");
m_NativeObj.Call(
"SettingAvaterFormMobile",  // Java函数名
 strObjectName,             // 传入的参数
strFuncName,                // 传入的参数
strFileName);               // 传入的参数

上面即调用主Activity上的SettingAvaterFormMobile函数.

Android原生代码要给Unity调用 还需要配置一些基本内容:

1.在Android项目的生成文件夹bin下命令行生成Jar包

在确认Android项目代码无误的情况下,到项目目录bin\classes下,打开命令行定位到这里,然后使用命令生成jar文件

jar -cvf xxx.jar * // xxx为文件名 可随意设置

2.Android项目需要取得原生jar包放到Unity项目文件夹Assets\Plugins\Android\bin目录(没有就自行创建) ,再取 AndroidManifest.xml,res文件夹 ,放到 Assets\Plugins\Android文件夹下.如图:

3.对于Android项目源码包的获取,Unity4.x 和 5.x方法不一样,如果是Unity5 需要把项目目录bin\classes下编译的R.java生成文件删掉.

  • 对于iOS

由于iOS开发可以OC与C/C++之间无缝调用,所以其实调用iOS原生函数 是通过调用C/C++函数中转的.方法非常简单.在C#脚本端声明一个C++函数,即可直接调用:

//-------------------------------------------------------------------------
// 声明
[DllImport("__Internal")]
private static extern 
void SettingAvaterFormiOS(string strObjectName, string strFuncName, string strFileName);
//-------------------------------------------------------------------------
// 调用
#elif UNITY_IPHONE
 {
    SettingAvaterFormiOS(strObjectName, strFuncName, strFileName);
 }
#else
//-------------------------------------------------------------------------

若需要调用一个Android项目的NDK开发的C++函数,原理也是一样的.

iOS原生代码要给Unity调用 还需要配置一些基本内容:

把自行编写的iOS代码复制到Unity项目文件夹文件夹Assets\Plugins\IOS\下(没有就自行创建),如图

iOS/Android 对摄像机的调用与图片截取

  • 对于Andorid

Android打开照相机和打开相册选取照片非常简单,网上代码一吨:

// 打开摄像机获取图片
if(v.getId() == m_OpenCameraID)
{
    eResult = CommonUtil.ENUM_RESULT.eResult_Camera;
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);  
    intent.putExtra(
        MediaStore.EXTRA_OUTPUT, 
        Uri.fromFile(new File(Environment.getExternalStorageDirectory(), m_ImageFileName)));
    m_contextAct.startActivityForResult(intent, eResult.ordinal());
}
// 打开相册选取图片
else if(v.getId() == m_GetPictureID)
{
    eResult = CommonUtil.ENUM_RESULT.eResult_Picture;
    Intent intent = new Intent(Intent.ACTION_PICK, null);  
    intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_UNSPECIFIED); 
    m_contextAct.startActivityForResult(intent, eResult.ordinal());
}
  • 对于iOS

iOS打开照相机和打开相册选取照片非常简单,网上代码也一吨:

//-------------------------------------------------------------------------
// 关键实现
- (void)showPicker:(UIImagePickerControllerSourceType)type
{
    UIImagePickerController *picker = [[[UIImagePickerController alloc] init] autorelease];
    picker.delegate = self;
    picker.sourceType = type;  // 打开摄像机或者打开相册
    picker.allowsEditing = YES;// 图片是否可编辑
    
    if( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad )
    {
        Class popoverClass = NSClassFromString( @"UIPopoverController" );
        if( !popoverClass )
            return;
        
        _popoverViewController = [[popoverClass alloc] initWithContentViewController:picker];
        [_popoverViewController setDelegate:self];

        [_popoverViewController presentPopoverFromRect:CGRectMake( 0, 0, 128, 128 )
                                                inView:UnityGetGLViewController().view
                              permittedArrowDirections:UIPopoverArrowDirectionAny
                                              animated:YES];
    }
    else
    {
        UIViewController *vc = UnityGetGLViewController();
        [vc presentModalViewController:picker animated:YES];
    }
}
//------------------------------------------------------------------------- 

iOS/Android 对图片的IO操作

获取的图片文件,可大可小,我们不能直接传string回Unity,所以可以事先保存到本地目录下.最佳的目录是Application.persistentDataPath.

  • 对于Android

这个目录就是:"/mnt/sdcard/Android/data/" + packageID + "/files".(packageID为APP包名)保存图片文件代码片段:

FileOutputStream fOut = null;
try
{
    String strPackgeName = getApplicationInfo().packageName;
    String path = "/mnt/sdcard/Android/data/" + strPackgeName + "/files";
    File destDir = new File(path);
    if (!destDir.exists()) 
    {
        destDir.mkdirs();
    }
    
    fOut = new FileOutputStream(path + "/" + m_ImageFileName) ;
} 
catch (FileNotFoundException e)
{
    e.printStackTrace();
}

photo.compress(Bitmap.CompressFormat.PNG, 100, fOut);

try 
{
    fOut.flush();
} 
catch (IOException e) 
{
    e.printStackTrace();
}

try 
{
    fOut.close();
} 
catch (IOException e) 
{
    e.printStackTrace();
}
  • 对于iOS

这个目录就是:Application/packageID/Documents.(packageID为APP包名)
代码片段:

NSString * DocumentsPath = 
[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];

NSFileManager *fileManager = 
[NSFileManager defaultManager];

[fileManager createDirectoryAtPath:DocumentsPath
 withIntermediateDirectories:YES 
attributes:nil 
error:nil];

[fileManager createFileAtPath:[DocumentsPath stringByAppendingString:m_pstrFileName] 
contents:imgData attributes:nil];

如此获取的图片就保存到了指定的目录中.这个时候只要告诉回调到Unity通知一下 即可.

上传图片

设置了用户头像,一般都会有上传头像到服务器的功能,关于C#上传图片到服务器网上也也有一吨的版本,但是Unity官方文档中的是如下:

//-------------------------------------------------------------------------
IEnumerator __UploadPNG()
{
    var bytes = m_texture2D.EncodeToPNG();
    var form = new WWWForm();
    form.AddField("frameCount", Time.frameCount.ToString());
    form.AddBinaryData("avatarPicture", bytes, "avatar.png", "image/png");
    // m_ImageUpDownURL URL上传接口
    var w = new WWW(m_ImageUpDownURL, form);
    yield return w;
    if (!string.IsNullOrEmpty(w.error))
    {
        Debug.Log(w.error);
    }
    else
    {
        Debug.Log("Finished Uploading Image");
    }
}
//-------------------------------------------------------------------------

参考博文:

  1. http://blog.csdn.net/poem_qianmo/article/details/40723789
  2. http://onevcat.com/2013/07/shader-tutorial-1/
  3. http://docs.unity3d.com/Manual/SL-SurfaceShaders.html
  4. http://http.developer.nvidia.com/CgTutorial/cg_tutorial_chapter05.html
  5. http://blog.csdn.net/candycat1992/article/category/1782159
  6. http://www.xuanyusong.com/archives/1493

-EOF-