选择你要开发的应用,点击该应用下方对应的“应用密钥”
在跳转页面,获取ApplicationID,此ID将会在初始化SDK中使用到。
获取ApplicationID后,下载SDK,开发者可以根据自己的需求选择相应的iOSSDK或AndroidSDK,点击下载即可。
一、在你的项目根目录下创建"libs"目录,将下载的BmobSDK文件放入该目录下。
二、在你的应用程序中添加相应的权限:
packagecom.bmob.example;importcn.bmob.Bmob;importandroid.app.Activity;importandroid.os.Bundle;publicclassMainActivityextendsActivity{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){//TODOAuto-generatedmethodstubsuper.onCreate(savedInstanceState);//初始化BmobSDK//使用时请将第二个参数ApplicationID替换成你在Bmob服务器端创建的ApplicationIDBmob.initialize(this,"YourApplicationID");}}简介Bmob平台为您的移动应用提供了一个完整的后端解决方案,我们提供轻量级的SDK开发包,让开发者以最小的配置和最简单的方式使用Bmob平台提供的服务,进而完全消除开发者编写服务器代码以及维护服务器的操作。
Bmob致力于为开发者提供快速开发服务,为方便大家更好的理解BmobSDK能够做的事情,我们特意为大家提供了一些源码,大家可以下载之后,嵌入Bmob的AppKey,再打包运行。
阅读源码是一种良好的习惯!!
在Bmob平台注册后,每个账户可创建多个应用程序,创建的每个应用程序都有其独自的应用程序ID,此后所有的应用程序将凭其ID进行BmobSDK的使用。即使只有一个应用程序,也可以以不同的版本进行测试和生产。
目前为止,我们支持的数据类型有String、Integer、Boolean、ArrayList以及BmobObject对象类型。同时Bmob也支持BmobDate、BmobGeoPoint、BmobFile数据类型。
一个对象对应了数据表中的一条数据,也可以理解为应用程序中的JavaBean.
publicclassGameScoreextendsBmobObject{privateStringplayerName;privateIntegerscore;privateBooleancheatMode;privateBmobFilepic;publicStringgetPlayerName(){returnplayerName;}publicvoidsetPlayerName(StringplayerName){this.playerName=playerName;}publicIntegergetScore(){returnscore;}publicvoidsetScore(Integerscore){this.score=score;}publicBooleangetCheatMode(){returncheatMode;}publicvoidsetCheatMode(BooleancheatMode){this.cheatMode=cheatMode;}publicBmobFilegetPic(){returnpic;}publicvoidsetPic(BmobFilepic){this.pic=pic;}}类名和表名的关系//这时候实际操作的表是T_a_bpublicclassGameScoreextendsBmobObject{privateStringplayerName;privateIntegerscore;privateBooleancheatMode;privateBmobFilepic;publicGameScore(){this.setTableName("T_a_b");}publicStringgetPlayerName(){returnplayerName;}//其他方法,见上面的代码}当然了,你也可以在GameScore实例中动态调用setTableName方法,实现操作可变表(如根据日期建立表来存储信息)的可能。
如果您使用了setTableName方法来自定义表名,那么在对该表进行数据查询的时候必须使用以下方法来进行查询。需要注意的是查询的结果是一个JSONArray,您需要自行解析JSONArray中的数据来进行使用。
添加数据非常简单,任何BmobObject对象都具有save方法可以用于将当前对象的内容保存到服务端。例如,你现在要保存一条游戏分数的记录,可以这样做:
GameScoregameScore=newGameScore();gameScore.setPlayerName("Barbie");gameScore.setScore(89);gameScore.setCheatMode(false);gameScore.save(mContext,newSaveListener(){@OverridepublicvoidonSuccess(){//TODOAuto-generatedmethodstubtoast("添加数据成功,返回objectId为:"+gameScore.getObjectId());}@OverridepublicvoidonFailure(intcode,Stringarg0){//TODOAuto-generatedmethodstub//添加失败}});运行完以上代码后,数据即可保存到服务器端。为了确认数据是否真的已经保存成功,你可以在Bmob服务器端你应用程序的数据浏览项目中进行查看。你应该看到类似这样的结果:
objectId:"0c6db13c",score:89,playerName:"Barbie",cheatMode:false,createdAt:"2013-09-2710:32:54",updatedAt:"2013-09-2710:32:54"注:
数据的查询可能是每个应用都会频繁使用到的,BmobSDK中提供了BmobQuery类,它提供了多样的方法来实现不同条件的查询,同时它的使用也是非常的简单和方便的。
查询某个数据表中的所有数据是非常简单的查询操作,例如:查询所有人员的信息。
BmobQuery
当我们知道某条数据的objectId时,就可以根据objectId直接获取单条数据对象。例如:查询objectId为a203eba875的人员信息。
BmobQuery
例如:如果要过滤掉特定键的值可以使用addWhereNotEqualTo方法。比如需要查询playerName不等于“Barbie”的数据时可以这样写:
query.addWhereNotEqualTo("playerName","Barbie");当然,你可以在你的查询操作中添加多个约束条件,来查询符合要求的数据。
query.addWhereNotEqualTo("playerName","Barbie");//名字不等于Barbiequery.addWhereGreaterThan("score",60);//条件:分数大于60岁各种不同条件的比较查询:
//分数<50query.addWhereLessThan("score",50);//分数<=50query.addWhereLessThanOrEqualTo("score",50);//分数>50query.addWhereGreaterThan("score",50);//分数>=50query.addWhereGreaterThanOrEqualTo("score",50);如果你想查询匹配几个不同值的数据,如:要查询“Barbie”,“Joe”,“Julia”三个人的成绩时,你可以使用addWhereContainedIn方法来实现。
String[]names={"Barbie","Joe","Julia"};query.addWhereContainedIn("playerName",Arrays.asList(names));相反,如果你想查询排除“Barbie”,“Joe”,“Julia”这三个人的其他同学的信息,你可以使用addWhereNotContainedIn方法来实现。
比如,你想查询2015年2月11号之前的Person数据,那么可以使用addWhereLessThan或者addWhereLessThanOrEqualTo(包含当天)来查询。如果想查询之后的数据,则可以使用addWhereGreaterThan或addWhereGreaterThanOrEqualTo(包含当天)来查询。
BmobQuery
query.setLimit(10);//限制最多10条数据结果作为一页在数据较多的情况下,在setLimit的基础上分页显示数据是比较合理的解决办法,setSKip方法可以做到跳过查询的前多少条数据来实现分页查询的功能。默认情况下Skip的值为10。
对应数据的排序,如数字或字符串,你可以使用升序或降序的方式来控制查询数据的结果顺序:
//根据score字段升序显示数据query.order("score");//根据score字段降序显示数据query.order("-score");//多个排序字段可以用(,)号分隔query.order("-score,createdAt");说明:多个字段排序时,先按第一个字段进行排序,再按第二个字段进行排序,依次进行。
如果你只是想统计满足查询对象的数量,你并不需要获取所有匹配对象的具体数据信息,可以直接使用count替代findObjects。例如,查询一个特定玩家玩的游戏场数:
BmobQuery
BmobQuery
如果你要获得某个字段匹配特定BmobObject的对象列表,你可以像查询其他数据类型一样使用addWhereEqualTo来查询。例如:每个Weibo对象都包含一个BmobUser对象在它的author字段上,现在你想查询当前用户发布的所有微博信息,如下:
query.include("weibo.author");这里需要注意的是:
1、include的查询对象只能为BmobPointer类型,而不能是BmobRelation类型。
2、如果你想include两个对象,你可以这样做:
query.include("Comment,User");但不能如下的做法:
query.include("Comment");query.include("User");缓存查询缓存查询通常是将查询结果缓存在磁盘上。当用户的设备处于离线状态时,就可以从缓存中获取数据来显示。或者在应用界面刚刚启动,从网络获取数据还未得到结果时,先使用缓存数据来显示。这样可以让用户不必在按下某个按钮后进行枯燥的等待。默认的查询操作是没有启用缓存的,开发者可以使用setCachePolicy方法来启用缓存功能。例如:优先从缓存获取数据,如果获取失败再从网络获取数据。
bmobQuery.setCachePolicy(CachePolicy.CACHE_ELSE_NETWORK);//先从缓存获取数据,如果没有,再从网络获取。bmobQuery.findObjects(this,newFindListener
只从网络获取数据,且不会将数据缓存在本地,这是默认的缓存策略。
只从缓存读取数据,如果缓存没有数据会导致一个BmobException,可以忽略不处理这个BmobException.
只从网络获取数据,同时会在本地缓存数据。
先从缓存读取数据,如果没有,再从网络获取。
先从缓存取数据,无论结果如何都会再次从网络获取数据。也就是说会产生2次调用。通常的用法是先快速取出缓存数据展示view,然后再后台连接网络取得最新数据,取到后用来自网络服务器的最新数据更新view。
如果需要操作缓存内容,可以使用BmobQuery提供的方法做如下操作:
有的时候,一张表的数据列比较多,而我们只想查询返回某些列的数据时,我们可以使用BmobQuery对象提供的addQueryKeys方法来实现。如下所示:
BmobQuery
更新一个对象也是非常简单。例如:将GameScore表中objectId为0c6db13c的游戏分数修改为77.
GameScoregameScore=newGameScore();gameScore.setScore(77);gameScore.update(this,"0c6db13c",newUpdateListener(){@OverridepublicvoidonSuccess(){//TODOAuto-generatedmethodstubtoast("更新成功:");}@OverridepublicvoidonFailure(intcode,Stringmsg){//TODOAuto-generatedmethodstubtoast("更新失败:"+msg);}});删除数据从服务器删除对象。例如:将GameScore表中objectId为dd8e6aff28的数据删除。
GameScoregameScore=newGameScore();gameScore.setObjectId("dd8e6aff28");gameScore.delete(this,newDeleteListener(){@OverridepublicvoidonSuccess(){//TODOAuto-generatedmethodstubtoast("删除成功");}@OverridepublicvoidonFailure(intcode,Stringmsg){//TODOAuto-generatedmethodstubtoast("删除失败:"+msg);}});删除字段你可以在一个对象中删除一个字段,通过remove操作:
GameScoregameScore=newGameScore();gameScore.setObjectId("dd8e6aff28");gameScore.remove("score");//删除GameScore对象中的score字段gameScore.update(this,newUpdateListener(){@OverridepublicvoidonSuccess(){//TODOAuto-generatedmethodstubtoast("删除GameScore对象中的score字段成功");}@OverridepublicvoidonFailure(intcode,Stringmsg){//TODOAuto-generatedmethodstubtoast("删除GameScore对象中的score字段失败:"+msg);}});数组对于数组型数据,BmobSDK提供了3种操作来原子性地更改一个数组字段:add、addAll在一个数组字段的后面添加一些指定的对象(包装在一个数组内)addUnique、addAllUnique只会在原本数组字段中没有这些对象的情形下才会添加入数组,插入数组的位置不固定的removeAll从一个数组字段的值内移除指定的数组中的所有对象
给一个数据对象中的数组类型字段添加数据可以使用以下方法添加:
Personp=newPerson();p.add("hobby","唱歌");//添加一个值到hobby字段中,hobby为数组类型//p.addAll("hobby",Arrays.asList("游泳","看书"));//一次添加多个值到hobby字段中p.save(this,newSaveListener(){@OverridepublicvoidonSuccess(){//TODOAuto-generatedmethodstubtoast("保存成功");}@OverridepublicvoidonFailure(intcode,Stringmsg){//TODOAuto-generatedmethodstubtoast("保存失败:"+msg);}});更新数组数据举个例子,hobby(爱好)是一个数组类型的字段,那么我们可以在hobby字段中加入一些爱好,只有在hobby字段中不包含这些爱好的情况下才会被加入:
Personp=newPerson();p.setObjectId("d32143db92");p.addUnique("hobby","爬山");//添加一个值到hobby字段中//p.addAllUnique("hobby",Arrays.asList("游泳","羽毛球"));//一次添加多个值到hobby字段中p2.update(this,newUpdateListener(){@OverridepublicvoidonSuccess(){//TODOAuto-generatedmethodstubtoast("更新爱好成功");}@OverridepublicvoidonFailure(intcode,Stringmsg){//TODOAuto-generatedmethodstubtoast("更新爱好失败:"+msg);}});查询数组数据对于字段类型为数组的情况,可以查找字段中的数组值包含有xxx的对象:
BmobQuery
由于关联关系讲解起来比较复杂,以下用一个简单的案例来说明在Bmob中是如何使用关联关系的,最后会提供相应的源码。这个场景是这样的:我们生活中每个人都可能会办理多张银行卡,而每张银行卡的登记人只有一个。从这个场景可以看出有两个对象,一个是人,一个是银行卡。
我们接下来需要在Web端创建对应的表,分别是用户表和银行卡表,其中用户表我们直接使用Bmob提供的系统表User表。在创建数据表的字段的时候,当选择字段类型为Pointer或Relation时,会提示你选择该字段所指向或关联的数据表。如下图所示:
根据本案例的场景,我们需要在User表中多增加一列为cards,数据类型为Relation,然后创建一个银行卡信息表(BankCard),银行卡表的主要结构如下:bankNameString银行名称cardNumberString银行卡号userPointer<_User>银行卡用户
为了更直观的展示数据表的结构,我将两个表的截图贴上,以供参考:
用户表(注意cards字段)
银行卡表(注意user字段)
接下来我们需要创建User表和BankCard表对应的数据对象,User表对应的数据对象的代码如下:
BankCard表对应的数据对象的代码如下:
publicclassBankCardextendsBmobObject{/***银行卡号*/privateStringcardNumber;/***银行名称*/privateStringbankName;/***户主*/privateMyUseruser;publicStringgetCardNumber(){returncardNumber;}publicvoidsetCardNumber(StringcardNumber){this.cardNumber=cardNumber;}publicStringgetBankName(){returnbankName;}publicvoidsetBankName(StringbankName){this.bankName=bankName;}publicMyUsergetUser(){returnuser;}publicvoidsetUser(MyUseruser){this.user=user;}}这里需要注意的是:1、类名要和表名保持一致。2、MyUser属性对应为Pointer的指针类型。
接下来我们就从代码层次上来讲解,怎么样来操作这些关联关系的数据。首先我们来讲添加关联关系。在我们创建一张银行卡信息时,需要指定这张卡的户主(user),这就是添加的一对一的关联关系。代码如下:
/***创建一条银行卡信息到BankCard表中,并关联到用户的银行卡信息中*@parambankName银行名称*@paramcardNumber银行卡号*/privatevoidsaveBankCardInfo(StringbankName,StringcardNumber){if(TextUtils.isEmpty(user.getObjectId())){toast("当前用户的object为空");return;}card=newBankCard();card.setBankName(bankName);//设置银行名称card.setCardNumber(cardNumber);//设置银行卡号card.setUser(user);//设置银行卡户主card.save(this,newSaveListener(){@OverridepublicvoidonSuccess(){//TODOAuto-generatedmethodstubtoast("成功保存一条银行卡信息到BankCard表中");addCardToUser();}@OverridepublicvoidonFailure(intarg0,Stringarg1){//TODOAuto-generatedmethodstubtoast("很遗憾,保存一条银行卡信息到BankCard表中失败了");}});}修改关联关系当我们的这张银行卡创建成功后,不仅仅只是设置银行卡的户主就可以来,我们还需要更新户主的信息,也就是将当前银行卡关联到用户的cards列中。这就是修改关联关系,代码如下:
/***添加银行卡到用户的银行卡信息中*/privatevoidaddCardToUser(){if(TextUtils.isEmpty(user.getObjectId())||TextUtils.isEmpty(card.getObjectId())){toast("当前用户或者当前Card对象的object为空");return;}BmobRelationcards=newBmobRelation();cards.add(card);user.setCards(cards);user.update(this,newUpdateListener(){@OverridepublicvoidonSuccess(){//TODOAuto-generatedmethodstubtoast("已成功添加到用户的银行卡信息中");}@OverridepublicvoidonFailure(intarg0,Stringarg1){//TODOAuto-generatedmethodstubtoast("很遗憾,用户的银行卡信息添加失败");}});}上面的代码将某银行卡添加到了用户的银行卡信息中,还有一种情况是从用户的银行卡信息中删除掉某银行卡的信息,在现实生活中我叫注销我的银行卡。代码示例如下:
/***删除用户信息中的某银行卡信息*/privatevoidremoveCardToUser(){if(TextUtils.isEmpty(user.getObjectId())||TextUtils.isEmpty(card.getObjectId())){toast("当前用户或者当前Card对象的object为空");return;}BmobRelationcards=newBmobRelation();cards.remove(card);user.setCards(cards);user.update(this,newUpdateListener(){@OverridepublicvoidonSuccess(){//TODOAuto-generatedmethodstubtoast("在用户信息中已成功移除该银行卡信息");}@OverridepublicvoidonFailure(intarg0,Stringarg1){//TODOAuto-generatedmethodstubtoast("很遗憾,移除失败");}});}查询关联关系需求1:查询我的所有银行卡信息,代码如下:
/***查询我的所有银行卡信息*/privatevoidfindMyCards(){BmobQuery
在BmobObject对象中提供了三种用于批量操作的方法,分别是insertBatch、updateBatch、deleteBatch,批量添加、更新、删除。
很多应用可能会有计数器功能的需求(并发请求会出现这个问题),比如某条信息被点赞多少次,如果多人同时操作,如果用普通的更新方法的话,可能会导致数据不一致的情况。为此,Bmob提供了原子计数器来保证原子性的修改某一数值字段的值。注意:原子计数器只能对应用于Web后台的Number字段,和实体类实现中的Integer对象类型(类中请不要用int类型)。
gameScore.increment("score");//分数递增1gameScore.update(this,updateListener);您还可以通过increment(key,amount)方法来递增或递减任意幅度的数字
创建文件对象方式如下:
StringpicPath="sdcard/temp.jpg";BmobFilebmobFile=newBmobFile(newFile(picPath));上传单一文件文件分片上传的方法非常简单,示例代码如下:
StringpicPath="sdcard/temp.jpg";BmobFilebmobFile=newBmobFile(newFile(picPath));bmobFile.uploadblock(this,newUploadFileListener(){@OverridepublicvoidonSuccess(){//TODOAuto-generatedmethodstub//bmobFile.getUrl()---返回的上传文件的地址(不带域名)//bmobFile.getFileUrl(context)--返回的上传文件的完整地址(带域名)toast("上传文件成功:"+bmobFile.getFileUrl(context));}@OverridepublicvoidonProgress(Integervalue){//TODOAuto-generatedmethodstub//返回的上传进度(百分比)}@OverridepublicvoidonFailure(intcode,Stringmsg){//TODOAuto-generatedmethodstubtoast("上传文件失败:"+msg);}});批量上传文件BmobSDK_V3.2.7新增批量上传文件的方法,使用起来也很简单,示例代码如下:
bmobQuery.findObjects(this,newFindListener
注:
1、单个文件上传大小不可超过200M;
2、文件分片上传的大小不可超过200M;
3、有时候使用upload方式上传不超过10M的文件的时候会出现OOM异常,故,建议开发者使用uploadblock(分片上传)方法来上传文件。
4、文件的批量上传是BmobSDK_v3.2.7版本才提供的功能,如需使用,请更新版本。
1、获取缩略图
如果你的BmobFile对象是保存的图片类型的文件,那么当你需要使用缩略图功能的时候,可以使用loadImageThumbnail方法来获取改图片的缩略图。
bmobFile.loadImageThumbnail(this,imageView,300,300);你还可以指定获取缩略图的图片质量
bmobFile.loadImageThumbnail(this,imageView,300,300,100);2、获取图片
很多时候您可能只是想直接加载图片来显示,那么你可以使用loadImage方法来加载原图。
bmobFile.loadImage(this,imageView);同样您也可以指定加载原图显示的大小
bmobFile.loadImage(this,imageView,300,300);3、缩略图的案例源码
新版文件管理是通过BmobProFile类(自BmobSDKv3.2.9开始)完成的,其提供了文件的单一上传、批量上传、文件下载、生成缩略图等功能,
BmobProFile和BmobFile两者之间是不兼容的,也就是说不能用BmobFile类上传的成功后得到的文件名再用BmobProFile类提供的下载方法来下载。
单一文件上传只需要调用BmobProFile类提供的静态方法:upload,示例代码如下:
BTPFileResponseresponse=BmobProFile.getInstance(MainActivity.this).upload(filePath,newUploadListener(){@OverridepublicvoidonSuccess(StringfileName,Stringurl){//TODOAuto-generatedmethodstubdialog.dismiss();showToast("文件已上传成功:"+fileName);}@OverridepublicvoidonProgress(intratio){//TODOAuto-generatedmethodstubBmobLog.i("MainActivity-onProgress:"+ratio);}@OverridepublicvoidonError(intstatuscode,Stringerrormsg){//TODOAuto-generatedmethodstubshowToast("上传出错:"+errormsg);}});onSuccess方法参数:
1、fileName:文件名(带后缀),这个文件名是唯一的,开发者需要记录下该文件名,方便后续下载该文件。
2、url:文件服务器地址(如果你上传的是图片类型的文件,此url地址并不能直接在浏览器查看(会出现404错误),需要经过URL签名得到真正的可访问的URL地址)。
1、使用场景:
开发者上传的如果是图片且希望能够访问完整的URL地址用来客户端直接显示图片,那么就需要用到URL签名。
2、签名认证步骤:
1)、开启签名认证:
开发者需要在web后台开启文件管理的URL签名认证:
文件管理-->基本配置-->设置SecretKey-->开启-->保存
注:此处的secretKey可任意填写,它是专门针对文件服务的,和"应用密钥"中的数据服务使用到的SecretKey是不一样的。
此部分为配置了URL的签名认证安全的开发者使用,若没配置,则按照正常处理。
2)、URL签名说明:
开启签名认证的URL地址格式:
未开启签名认证的URL地址格式:
URL=url(文件上传成功之后返回的url地址)t=(客户端类型)&a=(应用密钥中的AccessKey)
1、t:客户端类型(1~19代表SDK客户端,1:IOS,2:Android,3:wp,…,20:官网后台;21:其他网站)
2、AccessKey:在web后台的应用密钥中查看
4、Token:Token签名使用了web后台的文件管理中设置的SecretKey,开发者要注意此值的安全不被泄漏.
3)、URL签名步骤:
请求的文件名称fileName:dfwsdweqe0012.jpg;
假如请求参数为:
当前客户端类型:t=1//注释:Android
App的AccessKey:a=b63737a2825821fc3208b8a80a524da
当前的密钥SecretKey:abcdefg
组装请求URI:
Uri=/dfwsdweqe0012.jpgt=1&a=b63737a2825821fc3208b8a80a524da&e=1415697363
得到Token:
1、针对Uri进行HMAC-SHA1算法签名;
2、对签名后的字符串进行URL安全Base64编码;
3、编码后即为要要发送的token。
伪代码如下:
Token=urlbase64_encode(hmacsha1(Uri,secretKey));
得到最终的发送请求的URL为:
注:1、以上所有的参数名(t,a,e,token)均为小写,参数顺序为t,a,e,token,uri、secretkey等编码格式都为utf-8。
2、URL安全的Base64编码方式的基本过程是先将内容以Base64格式编码为字符串,然后检查该编码后的字符串,将字符串中的加号+换成中划线-,斜杠/换成下划线_,得到最终的字符串;
4)、URL签名方法:
鉴于URL签名比较复杂,BmobSDKV3.3.0的BmobProFile类为开发者提供了获取URL签名的方法:signURL(V3.3.2已修改为BmobProFile类的内部方法)
/***@paramfileName:文件名*@paramfileUrl:文件url地址*@paramaccessKey:web应用密钥中的AccessKey*@parameffectTime:有效时长(秒)*@paramsecretKey:密钥*@return可访问的URL地址*/StringURL=BmobProFile.getInstance(MainActivity.this).signURL(StringfileName,StringfileUrl,StringaccessKey,longeffectTime,StringsecretKey)未开启URL签名认证的示例代码如下:
1、fileName/fileUrl:表示上传(批量上传)成功后得到的文件名/文件服务器地址。
2、effectTime:表示这个URL请求的有效时长,单位为秒,一旦超过有效时长,则该URL请求失效。
3、若开发者未开启URL签名认证,则前三个参数必填,后面的effectTime传0,secretKey传null即可。
4、若文件类型为图片类型,客户端需要直接显示的话,则不建议开启URL签名认证
BmobProFile同样提供了批量上传文件的静态方法:uploadBatch:示例代码如下:
BmobProFile.getInstance(MainActivity.this).uploadBatch(files,newUploadBatchListener(){@OverridepublicvoidonSuccess(booleanisFinish,String[]fileNames,String[]urls){//TODOAuto-generatedmethodstubif(isFinish){dialog.dismiss();}showToast(""+isFinish+"-----"+Arrays.asList(fileNames)+"----"+Arrays.asList(urls));}@OverridepublicvoidonProgress(intcurIndex,intcurPercent,inttotal,inttotalPercent){//TODOAuto-generatedmethodstubdialog.setProgress(curIndex);BmobLog.i("MainActivity-onProgress:"+curIndex+"---"+curPercent+"---"+total+"----"+totalPercent);}@OverridepublicvoidonError(intstatuscode,Stringerrormsg){//TODOAuto-generatedmethodstubdialog.dismiss();showToast("批量上传出错:"+statuscode+"--"+errormsg);}});}onProgress方法参数:
1、curIndex:表示当前第几个文件正在上传
2、curPercent:表示当前上传文件的进度值(百分比)
3、total:表示总的上传文件数
4、totalPercent:表示总的上传进度(百分比)
BmobProFile同样提供了文件下载的静态方法:download,只需要将上传文件后记录下来的文件名fileName(必须是通过BmobProFile类的upload方法得到的)作为参数即可,示例代码如下:
BmobProFile.getInstance(MainActivity.this).download(fileName,newDownloadListener(){@OverridepublicvoidonSuccess(StringfullPath){//TODOAuto-generatedmethodstubshowToast("下载成功:"+fullPath);}@OverridepublicvoidonProgress(StringlocalPath,intpercent){//TODOAuto-generatedmethodstubBmobLog.i("MainActivity-download-->onProgress:"+percent);dialog.setProgress(percent);}@OverridepublicvoidonError(intstatuscode,Stringerrormsg){//TODOAuto-generatedmethodstubdialog.dismiss();showToast("下载出错:"+statuscode+"--"+errormsg);}});注:
1、onProgress参数localPath:表示当前下载文件的地址,当下载进度不为100的时候,这个地址下面的文件是不完整的,只有一部分。
2、onSuccess参数fullPath:表示下载成功后文件的存储完整地址,和localpath的路径是一样的。
3、允许开发者自定义保存下载文件的目录名,可在Apllication中对其进行初始化配置。示例如下:
BmobConfigurationconfig=newBmobConfiguration.Builder(context).customExternalCacheDir("目录名").build();BmobPro.getInstance(context).initConfig(config);缩略图处理对图片进行缩略图处理,BmobProFile类提供了两种方式:
一种将生成缩略图的任务提交给服务器,由服务器来处理并同步返回生成后的服务器缩略图地址(submitThumnailTask);另一种是SDK提供的本地处理缩略图的方法(getLocalThumbnail)。
一、submitThumnailTask
示例代码如下:
BmobProFile.getInstance(MainActivity.this).submitThumnailTask(fileName,modelId,newThumbnailListener(){@OverridepublicvoidonSuccess(StringthumbnailName,StringthumbnailUrl){//TODOAuto-generatedmethodstub//此处得到的缩略图地址(thumbnailUrl)不一定能够请求的到,此方法为异步方法BmobLog.i("MainActivity-onSuccess:"+thumbnailName+"-->"+thumbnailUrl);}@OverridepublicvoidonError(intstatuscode,Stringerrormsg){//TODOAuto-generatedmethodstubBmobLog.i("MainActivity-onError:"+statuscode+"---"+errormsg);}});注:
A、请求参数:fileName:文件名,modelId:缩略图的规格类型ID
B、thumbnailName的格式:
fileName+"_"+modelId
如果fileName=f24af10cbc15476e9789afaf168c3b8e.jpg,modelId=1,那么thumbnailName=f24af10cbc15476e9789afaf168c3b8e.jpg_1。
C、目前Bmob提供的规格类型ID(modelId)有六种:
1--指定宽,高自适应,等比例缩放;
2--指定高,宽自适应,等比例缩放;
3--指定最长边,短边自适应,等比例缩放;
4--指定最短边,长边自适应,等比例缩放;
5--指定最大宽高,等比例缩放;
6--固定宽高,居中裁剪;
二、getLocalThumbnail
SDK提供了三种处理本地缩略图的方式:
一、指定规格ID
BmobProFile.getInstance(LocalThumbnailActivity.this).getLocalThumbnail(localPath,modelId,newLocalThumbnailListener(){@OverridepublicvoidonError(intstatuscode,Stringerrormsg){//TODOAuto-generatedmethodstubBmobLog.i("MainActivity-localThumbnail-->生成缩略图失败:"+statuscode+","+errormsg);}@OverridepublicvoidonSuccess(StringthumbnailPath){//TODOAuto-generatedmethodstubBmobLog.i("MainActivity-localThumbnail-->生成后的缩略图路径:"+thumbnailPath);}});二、指定规格ID、宽、高
BmobProFile.getInstance(LocalThumbnailActivity.this).getLocalThumbnail(localPath,modeId,width,height,newLocalThumbnailListener(){@OverridepublicvoidonError(intstatuscode,Stringerrormsg){//TODOAuto-generatedmethodstubshowToast("本地缩略图创建失败:"+statuscode+","+errormsg);}@OverridepublicvoidonSuccess(StringthumbnailPath){//TODOAuto-generatedmethodstubshowToast("本地缩略图创建成功:"+thumbnailPath);}});三、指定规格ID、宽、高、图片压缩质量
为了方便开发者对图片进行压缩处理,V3.3.3版本在获取本地缩略图的方法中新增了图片压缩质量(quality)参数,取值范围:0-100。示例代码如下:
BmobProFile.getInstance(LocalThumbnailActivity.this).getLocalThumbnail(localPath,modeId,width,height,quality,newLocalThumbnailListener(){@OverridepublicvoidonError(intstatuscode,Stringerrormsg){//TODOAuto-generatedmethodstubshowToast("本地缩略图创建失败:"+statuscode+","+errormsg);}@OverridepublicvoidonSuccess(StringthumbnailPath){//TODOAuto-generatedmethodstubshowToast("本地缩略图创建成功:"+thumbnailPath);}});注:
1、localPath:图片的本地路径,需要带后缀名
2、modelId:开发者应事先在应用管理后台(文件管理-->自定义版本-->缩略图配置版本)完成基本的生成缩略图的规格配置:
数据实时同步是一个超酷的功能!
SDK可以实现对数据表或行的监听,当这个表或者行的数据发生变化时,Bmob会立即将变化的信息告知SDK。这种服务非常适合做游戏开发(如,开发斗地主游戏,三个人同时监听一行数据的变化,任何一个人出牌都会将数据写入到这行数据中,其他人也就立即知道了)、群聊(一群人监听某个表的变化,任何人发言都会将数据写入到这个表中,其他人也可以立即知道了)等实时性要求很高的场景中。
使用数据实时功能,首先需要创建BmobRealTimeData对象,然后调用start方法连接服务器。
BmobRealTimeDatartd=newBmobRealTimeData();rtd.start(this,newValueEventListener(){@OverridepublicvoidonDataChange(JSONObjectdata){//TODOAuto-generatedmethodstubLog.d("bmob","("+data.optString("action")+")"+"数据:"+data);}@OverridepublicvoidonConnectCompleted(){//TODOAuto-generatedmethodstubLog.d("bmob","连接成功:"+rtd.isConnected());}});start方法中的ValueEventListener参数用于监听连接成功和数据变化的回调。当有数据变化时会通过onDataChange回调方法反馈到客户端。开发者只需要处理得到的data就可以了。
1、监听器不支持UI线程,在监听回调中请不要直接操作UI;
2、如果你要监听User、Installation等系统表的话,表名前需要加上“_”,例如:_User
在BmobRealTimeData对象连接成功后,就可以进行数据的监听了。BmobSDK提供了监听表和行的方法如下:
//监听表更新rtd.subTableUpdate(tableName);//监听表删除rtd.subTableDelete(tableName);//监听行更新rtd.subRowUpdate(tableName,objectId);//监听行删除rtd.subRowDelete(tableName,objectId);其中tableName为要监听的数据表名,objectId为要监听的数据行Id,通常比较保险的做法是在BmobRealTimeData对象的连接状态为true的情况下进行监听,代码如下:
if(rtd.isConnected()){//监听表更新rtd.subTableUpdate(tableName);}取消监听当开发者想取消监听某个行为是,可使用下面的方法:
//取消监听表更新rtd.unsubTableUpdate(testTableName);//取消监听表删除rtd.unsubTableDelete(testTableName);//取消监听行更新rtd.unsubRowUpdate(testTableName,objectId);//取消监听行删除rtd.unsubRowDelete(testTableName,objectId);用户管理用户是一个应用程序的核心。对于个人开发者来说,自己的应用程序积累到越多的用户,就会给自己带来越强的创作动力。因此Bmob提供了一个专门的用户类——BmobUser来自动处理用户账户管理所需的功能。
有了这个类,你就可以在你的应用程序中添加用户账户功能。
BmobUser除了从BmobObject继承的属性外,还有几个特定的属性:username:用户的用户名(必需)。password:用户的密码(必需)。email:用户的电子邮件地址(可选)。
很多时候,你的用户表还会有很多其他字段,如性别、年龄、头像等。那么,你需要对BmobUser类进行扩展,添加一些新的属性。示例代码如下所示:
publicclassSpecialUserextendsBmobUser{privatebooleansex;privateStringnick;publicbooleangetSex(){returnthis.sex;}publicvoidsetSex(booleansex){this.sex=sex;}publicStringgetNick(){returnthis.sex;}publicvoidsetNick(Stringnick){this.nick=nick;}}更多代码实现大家可以下载SDK,在里面的BmobExample中查找MyUser类,参考它的用法。
创建用户对象如下:
BmobUseruser=newBmobUser();注册用户你的应用程序可能会要求用户注册。下面的代码是一个典型的注册过程:
BmobUserbu=newBmobUser();bu.setUsername("sendi");bu.setPassword("123456");bu.setEmail("sendi@163.com");bu.signUp(this,newSaveListener(){@OverridepublicvoidonSuccess(){//TODOAuto-generatedmethodstubtoast("注册成功:");}@OverridepublicvoidonFailure(intcode,Stringmsg){//TODOAuto-generatedmethodstubtoast("注册失败:"+msg);}});在注册过程中,服务器会对注册用户信息进行检查,以确保注册的用户名和电子邮件地址是独一无二的。此外,对于用户的密码,你可以在应用程序中进行相应的加密处理后提交。
如果注册不成功,你可以查看返回的错误对象。最有可能的情况是,用户名或电子邮件已经被另一个用户注册。这种情况你可以提示用户,要求他们尝试使用不同的用户名进行注册。
你也可以要求用户使用Email做为用户名注册,这样做的好处是,你在提交信息的时候可以将输入的“用户名“默认设置为用户的Email地址,以后在用户忘记密码的情况下可以使用Bmob提供重置密码功能。
这里有两点需要注意的:
BmobUser.logOut(this);//清除缓存用户对象BmobUsercurrentUser=BmobUser.getCurrentUser(this);//现在的currentUser是null了更新用户很多情况下你可能需要修改用户信息,比如你的应用具备修改个人资料的功能,Bmob提供的用户更新方式有两种写法:
第一种:新建一个用户对象,并调用update(context,objectId,updateListener)方法来更新(推荐使用),示例:
BmobUsernewUser=newBmobUser();newUser.setEmail("xxx@163.com");BmobUserbmobUser=BmobUser.getCurrentUser(this);newUser.update(this,bmobUser.getObjectId(),newUpdateListener(){@OverridepublicvoidonSuccess(){//TODOAuto-generatedmethodstubtoast("更新用户信息成功:");}@OverridepublicvoidonFailure(intcode,Stringmsg){//TODOAuto-generatedmethodstubtoast("更新用户信息失败:"+msg);}});第二种:获取本地的用户对象,并调用update(context,updateListener)方法来更新(不推荐使用),示例:
查询用户和查询普通对象一样,只需指定BmobUser类即可,如下:
BmobQuery
User表是一个特殊的表,专门存储BmobUser对象。在浏览器端,你会看到一个User表旁边有一个小人的图标。
一旦你引入了一个密码系统,那么肯定会有用户忘记密码的情况。对于这种情况,我们提供了一种方法,让用户安全地重置起密码。
重置密码的流程很简单,开发者只需要求用户输入注册的电子邮件地址即可:
为方便大家了解如何用Bmob开发找回密码的功能,我们为大家准备了另外一份文档,详细见我们在Github中的文档:
emailVerified字段有3种状态可以考虑:
{"qq":{"openid":"AAC61872C459FB196AECFA9D6FEBA334","access_token":"19A1E9FB3E440B4D15DBB44a39946FD4","expires_in":7776000}}解除绑定解除第三方账号与BmobUser的绑定关系如下代码所示:
其中,最灵活的方法是通过ACL和角色,它的思路是每一条数据有一个用户和角色的列表,以及这些用户和角色拥有什么样的许可权限。
大多数应用程序需要对不同的数据进行灵活的访问和控制,这就可以使用Bmob提供的ACL模式来实现。例如:
用BmobSDK,你可以对这些数据设置一个默认的ACL,这样,即使黑客反编译了你的应用,获取到ApplicationKey,也仍然无法操作和破坏你的用户数据,确保了用户数据的安全可靠。而作为开发者,当你需要对这些数据进行管理时,可以通过超级权限Key(MasterKey)进行。
在没有显示指定的情况下,每一个BmobObject(表)中的ACL(列)属性的默认值是所有人可读可写的。在客户端想要修改这个权限设置,只需要简单调用BmobACL的setPublicReadAccess方法和setPublicWriteAccess方法,即:
BmobACLaCL=newBmobACL();aCL.setPublicReadAccess(true);aCL.setPublicWriteAccess(true);注意:可读可写是默认的权限,不需要写额外的代码。
Blogblog=newBlog();blog.setTitle("论电影的七个元素");blog.setContent("这是blog的具体内容");BmobACLacl=newBmobACL();//创建一个ACL对象acl.setPublicReadAccess(true);//设置所有人可读的权限acl.setWriteAccess(BmobUser.getCurrentUser(this),true);//设置当前用户可写的权限blog.setACL(acl);//设置这条数据的ACL信息blog.save(this,newSaveListener(){@OverridepublicvoidonSuccess(){//添加成功}@OverridepublicvoidonFailure(intcode,Stringmsg){//添加失败}});有时,用户想发表一篇不公开的日志,这种情况只有发布者才对这篇日志拥有读写权限,相应的代码如下:
Blogblog=newBlog();blog.setTitle("一个人的秘密");blog.setContent("这是blog的具体内容");BmobACLacl=newBmobACL();//创建ACL对象acl.setReadAccess(BmobUser.getCurrentUser(this),true);//设置当前用户可写的权限acl.setWriteAccess(BmobUser.getCurrentUser(this),true);//设置当前用户可写的权限blog.setACL(acl);//设置这条数据的ACL信息blog.save(this,newSaveListener(){@OverridepublicvoidonSuccess(){//添加成功}@OverridepublicvoidonFailure(intcode,Stringmsg){//添加失败}});角色管理上面的指定用户访问权限虽然很方便,但是对于有些应用可能会有一定的局限性。比如一家公司的工资系统,员工和公司的出纳们只拥有工资的读权限,而公司的人事和老板才拥有全部的读写权限。要实现这种功能,你也可以通过设置每个用户的ACL权限来实现,如下:
//创建公司某用户的工资对象WageInfowageinfo=newWageInfo();wageinfo.setWage(100000);//这里创建四个用户对象,分别为老板、人事小张、出纳小谢和自己BmobUserboss;BmobUserhr_zhang;BmobUsercashier_xie;BmobUserme;//创建ACL对象BmobACLacl=newBmobACL();//设置四个用户读的权限acl.setReadAccess(boos,true);acl.setReadAccess(hr_zhang,true);acl.setReadAccess(cashier_xie,true);acl.setReadAccess(me,true);//设置老板和人事小张对这个工资的写权限acl.setWriteAccess(boss,true);acl.setWriteAccess(hr_zhang,true);//设置工资对象的ACLwageinfo.setACL(acl);wageinfo.save(this,newSaveListener(){@OverridepublicvoidonSuccess(){//保存成功}@OverridepublicvoidonFailure(intcode,Stringmsg){//保存失败}});但是,一个公司的人事、出纳和员工不仅仅只有一个人,同时还会有离职、调换岗位以及新员工加入等问题存在。如果用上面的代码对公司的每个人进行一一设置的话是不现实的,既麻烦也很难维护。针对这个问题,我们可以利用BmobRole来解决。我们只需要对用户进行分类,每个分类赋予不同的权限。如下代码实现:
下面我们来说一下角色与角色之间的从属关系。用一个例子来说明下:一个互联网企业有移动部门,部门中有不同的小组,如Android开发组和IOS开发组。每个小组只拥有自己小组的代码读写权限,但这两个小组同时拥有核心库代码的读权限。
Bmob允许用户根据地球的经度和纬度坐标进行基于地理位置的信息查询。通过在BmobObject的查询中添加一个BmobGeoPoint的对象查询,你就可以实现轻松查找出离当前用户最接近的信息或地点的功能。
首先需要创建一个BmobGeoPoint对象。例如,创建一个东经116.39727786183357度,北纬39.913768382429105度的BmobGeoPoint对象:
BmobGeoPointpoint=newBmobGeoPoint(116.39727786183357,39.913768382429105);查询地理位置信息现在,你的数据表中有了一定的地理坐标对象的数据,这样可以测试找出最接近某个点的信息了。你可以使用BmobQuery对象的addWhereNear方法来这样做:
BmobQuery
要查询一个矩形范围内的信息可以使用addWhereWithinGeoBox来实现:
BmobGeoPointsouthwestOfSF=newBmobGeoPoint(116.10675,39.711669);BmobGeoPointnortheastOfSF=newBmobGeoPoint(116.627623,40.143687);BmobQuery
很多时候,单纯的前端代码是不能完成全部事情的,一些重要和复杂的业务逻辑还是希望能够在服务端中执行。比如:对比较大量的比赛数据进行排序,对某个网站进行资料采集和处理,获取用户的IP信息,等等。Bmob不仅提供了云端存储,还开放了云端的业务逻辑代码功能,也就是云端代码。
云端代码的执行有多种方法:
其中,在SDK中调用云端代码的方法如下:
AsyncCustomEndpointsace=newAsyncCustomEndpoints();//第一个参数是上下文对象,第二个参数是云端代码的方法名称,第三个参数是上传到云端代码的参数列表(JSONObjectcloudCodeParams),第四个参数是回调类ace.callEndpoint.callEndpoint(MainActivity.this,cloudCodeName,params,newCloudCodeListener(){@OverridepublicvoidonSuccess(Objectobject){//TODOAuto-generatedmethodstubtoast("云端usertest方法返回:"+object.toString());}@OverridepublicvoidonFailure(intcode,Stringmsg){//TODOAuto-generatedmethodstubtoast("访问云端usertest方法失败:"+msg);}});消息推送消息推送简介推送通知是让用户及时被通知、和你的应用保持联系的一种非常棒的方式,你可以快速而有效地通知到所有的用户,下面这个教程将会教你如何使用Bmob来推送消息。
二、在您的应用程序AndroidManifest.xml文件中添加相应的权限:
Push消息通过action=cn.bmob.push.action.MESSAGE的Intent把数据发送给客户端your.package.MyPushMessageReceiver,消息格式由应用自己决定,PushService只负责把服务器下发的消息以字符串格式透传给客户端。your.package.MyPushMessageReceiver代码示例如下:
publicclassMyPushMessageReceiverextendsBroadcastReceiver{@OverridepublicvoidonReceive(Contextcontext,Intentintent){//TODOAuto-generatedmethodstubif(intent.getAction().equals(PushConstants.ACTION_MESSAGE)){Log.d("bmob","客户端收到推送内容:"+intent.getStringExtra(PushConstants.EXTRA_PUSH_MESSAGE_STRING));}}}五、启动推送服务
在你的应用程序主Activity中调用如下方法:
六、在web端进行推送设置
七、在web端推送消息
在后台推送消息给Android和iOS两个平台的时候,有一些需要注意的:1、由于Android和iOS的提送机制不同,iOS要经过APNS,Android的推送完全是走Bmob的长连接服务,为兼容这个问题,如果你选择发送格式为“json”格式时,需要添加APNS兼容头部(见下面json的aps部分),推送内容格式如下:
{"aps":{"sound":"cheering.caf","alert":"这个是通知栏上显示的内容","badge":0},"xx":"json的key-value对,你可以根据情况添加更多的,客户端进行解析获取",}其中,sound是iOS接收时的声音,badge是iOS通知栏的累计消息数。
2、如果你选择发送格式为“text”时,推送内容为“推送消息测试。。。。”,Bmob会自动添加aps部分发送给APNS,,相当于自动生成如下的json格式的推送内容:
{"aps":{"alert":"推送消息测试。。。。",}}同时,也会发送给Android端,相当于自动生成如下的json格式的推送内容:
{"alert":"推送消息测试。。。。",}3、如果只是发送给Android端,大家可以自定义json格式的数据。
4、由于iOS的APNS的推送的大小是有限制的,默认最多256bytes,因此,如果你需要跨平台互通的话,需注意推送的内容不要太长。
八、源码下载
Bmob官方为大家准备了消息推送的视频教程,有需要的朋友可以移步浏览视频教程:
每一个Bmob的App被安装在用户的设备上后,如果要使用消息推送功能,BmobSDK会自动生成一个Installation对象。Installation对象包含了推送所需要的所有信息。举例:一个棒球的App,你可以让用户订阅感兴趣的棒球队,然后及时将这个球队的消息推送给用户。您可以使用BmobSDK,通过BmobInstallation对象进行一系列操作,就像你存储和获取其他的普通对象一样,比如BmobObject对象。
BmobInstallation对象有几个系统默认的特殊字段来帮助你进行设备定位等管理:
使用消息推送前,首先需要保存设备信息。
BmobInstallation.getCurrentInstallation(this).save();你还可以通过定义继承自BmobInstallation的JavaBean来为BmobInstallation对象添加更多的属性,用来定制更通用的推送。
publicclassMyBmobInstallationextendsBmobInstallation{privateintscore;publicintgetScore(){returnscore;}publicvoidsetScore(intscore){this.score=score;}}订阅频道和退订订阅频道订阅频道可使用subscribe方法
BmobInstallationinstallation=BmobInstallation.getCurrentInstallation(this);installation.subscribe("Giants");installation.subscribe("Mets");installation.save();退订频道退订频道可使用unsubscribe方法
BmobInstallationinstallation=BmobInstallation.getCurrentInstallation(this);installation.unsubscribe("Giants");installation.save();广播推送消息在客户端实现推送消息的功能,通过BmobPushManager对象来完成,比如给所有设备推送一条消息,如下:
BmobPushManagerbmobPush=newBmobPushManager(this);bmobPush.pushMessageAll("HelloBmob.");组播推送消息发送消息给订阅了Giants频道的用户
BmobPushManagerbmobPush=newBmobPushManager(this);BmobQuery
BmobPushManagerbmobPush=newBmobPushManager(this);BmobQuery
给Android平台的终端推送
BmobPushManagerbmobPush=newBmobPushManager(this);BmobQuery
BmobPushManagerbmobPush=newBmobPushManager(this);BmobQuery
发送给Android单个客户端
StringinstallationId="客户端installationId";BmobPushManagerbmobPush=newBmobPushManager(this);BmobQuery
短信服务的功能包括:
9001
内容:AppKeyisNull,PleaseinitializeBmobSDK.
含义:AppKey为空,请初始化。
9002
内容:Parsedataerror
含义:解析返回数据出错
9003
内容:uploadfileerror
含义:上传文件出错
9004
内容:uploadfilefailure
含义:文件上传失败
9005
内容:Abatchoperationcannotbemorethan50
含义:批量操作只支持最多50条
9006
内容:objectIdisnull
含义:objectId为空
9007
内容:BmobFileFilesizemustbelessthan10M.
含义:文件大小超过10M
9008
内容:BmobFileFiledoesnotexist.
含义:上传文件不存在
9009
内容:Nocachedata.
含义:没有缓存数据
9010
内容:Thenetworkisnotnormal.(Timeout)
含义:网络超时
9011
内容:BmobUserdoesnotsupportbatchoperations.
含义:BmobUser类不支持批量操作
9012
内容:contextisnull.
含义:上下文为空
9013
内容:BmobObjectObjectnames(databasetablename)formatisnotcorrect.
含义:BmobObject(数据表名称)格式不正确
9014
9015
含义:其他错误均返回此code
9016
内容:Thenetworkisnotavailable,pleasecheckyournetwork!
含义:无网络连接,请检查您的手机网络。
由于BmobAndroidSDK本身进行了代码混淆,因此,你在给应用打包编译混淆时,请不要混淆BmobSDK的代码,另外,任何继承自BmobObject、BmobUser的JavaBean请不要混淆。具体可参考BmobExample中proguard-project.txt的代码: