首页 文章 精选 留言 我的

精选列表

搜索[项目归档],共10000篇文章
优秀的个人博客,低调大师

【原】设置iOS项目BuildVersion自动增加

一、概念阐述:Build与Version的区别 在iOS中有两种“版本号”,也就是所谓的version号与build号,如下图所示: 我们用最简洁的语言来区分这两个版本号的区别以及用途如下: Version号:也称为Bundle versions string, sthort. appstore以及itune中产品介绍所用的版本号,多面向用户,多为两段式或者三段式,1.0.1,1.2等,通常作为版本升级的主要依据 Build号:也称为Bundle version. 开发者团队内部使用,方便追查bug,多用于内测过程中区分出不同产品。也就是相同Version下,Build号可以不同 二者在plist中也分别用不同的字段来表示 对于开发者而言,我们往往更关注Build号,也就是Bundle version。因此,本文旨在介绍一种方法,实现Bundle version自动标记,用以区分不同的内测产品。 二、Bundle version自动增加 Bundle version的表示方法用很多种,大致如下:时间表示法(e.g. 20150715)、字母表示法、纯数字表示法。本文采用最后的纯数字表示法,并且采用xcode对代码的编译次数作为bundle version。可以预见,这样的bundle version将呈现出递增趋势。但需要每次编译后都去修改xcode的工程设置以及plist吗?答案是否定的。APPLE已经提供了工具帮我们实现bundle version的自动递增。 具体设置步骤参加下图(图片转载自此处): 其中的脚本代码为: 1 xcrun agvtool next-version -all 三、More 如果是多人开发,会存在每个人开发的分支多次编译导致Build版本不准的情况,但不影响开发进程。对于开发我们需要注意的是每次测试测试前的Build版本。确保它增加,就,可以了!至于是否要release时增加,是否需要手动修改,这个可以根据实际情况调整。毕竟,Build版本号只是一个辅助的参数。 本文转自编程小翁博客园博客,原文链接:http://www.cnblogs.com/wengzilin/p/4648177.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

iOS 小项目--小费计算器

这个例子是 iPhone应用程序开发名师解析 上的一个小例子,基于Xcode4.3.1的工程开发 效果截图: 1.创建一个新工程叫TipCalculator; File->New->Project ->single View Application -> next. 2.布局界面 其中包含9个静态Label标签一个动态Label标签,他根据slider值的变化而能变化,然后是9个Textfield和一个slider滑动条 另外需要对TextField属性设置,text设置为0.00,然后键盘选择成Number Pad类型的,只需要对第一个最长的TextfIeld设置一下键盘类型就行,其他的不用设置,其他的8个标签显示了灰色数字,设置的是Placeholder属性; 3.设计代码,我们选择左上角的Editor图标,点击出现视图编辑框分为XIB文件,和TipCalculatorViewController.h文件 如果没有出现TipCalculatorViewController.h,我们可以根据Automatic文件进行切换 4.右键选中最长的那个TextField文件拖动到右边TipCalculatorViewController.h文件@end前面, 然后弹出一个框框,Connection选为Outlet,Storage选为Strong, 5.这样我们第一个TextField关联成功,其他的一样, 关联Slider时候,我们对他设置一些属性,(原本是最小值设为0最大值设为0.3但是我在拖动滑动条时候滑动条总是自动变为0,这样修改后问题就可以解决了),他还有一个和calculate的关联方法, 我们还需要添加两个方法,并声明一个NSString类的对象 总的代码为 #import <UIKit/UIKit.h> @interface TipCalculatorViewController : UIViewController { NSString *billTotal; } @property (strong, nonatomic) IBOutlet UITextField *billField; @property (strong, nonatomic) IBOutlet UITextField *tipFieldTen; @property (strong, nonatomic) IBOutlet UITextField *tipFieldFifteen; @property (strong, nonatomic) IBOutlet UITextField *tipFieldTwenty; @property (strong, nonatomic) IBOutlet UITextField *totalFieldTen; @property (strong, nonatomic) IBOutlet UITextField *totalFieldFifteen; @property (strong, nonatomic) IBOutlet UITextField *totalFieldTwenty; @property (strong, nonatomic) IBOutlet UITextField *tipFieldCustom; @property (strong, nonatomic) IBOutlet UITextField *totalFieldCustom; @property (strong, nonatomic) IBOutlet UISlider *customPercentSlider; @property (strong, nonatomic) IBOutlet UILabel *customLabel; -(IBAction)calculate:(id)sender;//计算小费 -(IBAction)backGrounfTap:(id)sender;//处理隐藏键盘 @end 6.因为本人在拖控件是界面设计的不够好,弹出键盘时会覆盖住下面两个TextField,所以添加了一个隐藏键盘的方法,我们把整个背景View视图当做一个大按钮,当输入完金额后点击背景就会隐藏键盘,还是选中XIB文件,然后把View类修改UIControl,然后打开关联事件,选中Touch Down 然后会弹出两个方法,backGrounfTap和calculate(注.原本是想写成backGroundTap,单词写错了变成backGrounfTap,为了其他地方不再修改,就按照backGrounfTap写了),xuanzhbackGrounfTap方法, //处理键盘 -(IBAction)backGrounfTap:(id)sender { [billField resignFirstResponder]; [tipFieldCustom resignFirstResponder]; [totalFieldCustom resignFirstResponder]; } 为什么只把三个TextField注册为了第一响应,完全按照自己意愿添加,但是最低我们要保证billField第一个添加上,其他的想添加不想添加都无所谓,只是个人觉得多添加的两个体验会好一点; 7.主要就是calculate方法实现部分 //当调出的键盘被触摸了某个数时或者某个按钮调用此方法 -(IBAction)calculate:(id)sender { // 标记是否是由用户触发 static BOOL toggle =YES; if (toggle) { // 设置标志位,此方法的下次调用由程序触发 toggle=NO; // 取出billField文本值 NSString *billFieldText = billField.text; // 将billFieldText字符串类型转换成浮点型 float newTotal = [billFieldText floatValue]; // 获取滑动条的值 float customTipPercent = customPercentSlider.value; // 事件由billField触发 if (sender == billField) { // 通过比较billField字符长度,检测billField值是否改变 if(billFieldText.length < billTotal.length) billTotal = [NSString stringWithFormat:@"%.02f",newTotal/10]; // 用户输入数字 else billTotal = [NSString stringWithFormat:@"%.02f",newTotal*10]; // 取出billTotal赋给billField文本值 billField.text = billTotal; // 将billTotal转换成浮点型,newTotal设置为新值 newTotal = [billTotal floatValue]; // 按照10% 15% 20%计算小费值 float tenTip = newTotal*0.1; float fifteenTip = newTotal*0.15; float twentyTip = newTotal*0.2; // 显示Tip栏小费值 tipFieldTen.text = [NSString stringWithFormat:@"%.02f",tenTip]; tipFieldFifteen.text = [NSString stringWithFormat:@"%.02f",fifteenTip]; tipFieldTwenty.text = [NSString stringWithFormat:@"%.02f",twentyTip]; // 设置toatal栏中显示值 totalFieldTen.text = [NSString stringWithFormat:@"%.02f",newTotal+tenTip]; totalFieldFifteen.text = [NSString stringWithFormat:@"%.02f",newTotal+fifteenTip]; totalFieldTwenty.text = [NSString stringWithFormat:@"%.02f",newTotal+twentyTip]; } // 当事件由customPercentSlider触发时 else if (sender == customPercentSlider) { // 显示滑动条变化值 customLabel.text = [NSString stringWithFormat:@"%i%%",(int)customTipPercent]; // 把按钮值赋给滑动条的值,其中对浮点型值进行了强制转换 customPercentSlider.value=(int)customTipPercent; customTipPercent = (int)customTipPercent; } // 计算小费,因为滑动条值为0~30,所以需要除以100求出小费率 float customTip = customTipPercent/100 * newTotal; tipFieldCustom.text = [NSString stringWithFormat:@"%.02f",customTip]; // 表示应付的总金额 totalFieldCustom.text =[NSString stringWithFormat:@"%.02f",customTip+newTotal]; } else { toggle=YES; } } 8.当我们输入时候,有个特别要求,假如用户小费12元,我们应输入1200,然后他们会自动变成12.00元,主要通过 通过比较 if billTotal 用户输入数字 else billTotal 实现方法,通过比较billField原来字符串长度检测用户是否改变金额,来变得小费和总的金额; 源代码:http://download.csdn.net/detail/duxinfeng2010/4464095 本文转自新风作浪 51CTO博客,原文链接:http://blog.51cto.com/duxinfeng/1208729,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android 项目开发基础再回顾(一)

1,主activity_splash: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/launcher_bg"//设置初始背景图片 tools:context=".SplashActivity" > <TextView android:id="@+id/tv_version_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true"#把这个textview 放到中间 android:shadowDx="1//这个指的是相对于原字体在x方向上的偏移量 android:shadowDy="1" android:shadowColor="#f00"//黑色 android:shadowRadius="1"//表示阴影的模糊程度 android:textSize="16sp" android:text="版本名称" /> <ProgressBar //加载滚动条 android:layout_below="@id/tv_version_name" android:layout_centerHorizontal="true" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout> 2,副activity_home <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:text="HomeActivity" android:textSize="20sp" android:textColor="#000" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> 3,让第二个活动可以启动 <activity android:name="com.example.moblesafe73.HomeActivity"/> 4,接下来创造两个工具类, 一个是将流转化为字符串 mport java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; public class StreamUtil { public static String StreamToString(InputStream is) { //1.在读取的过程中,将读取的内容存取到缓存中,然后一次性用字符转化成字符串 ByteArrayOutputStream bos=new ByteArrayOutputStream(); //2.读取操作,读到没有为止(循环) byte[] buffer=new byte[1024]; //3.记录读取内容的临时变量 int temp=-1; try { while((temp=is.read(buffer))!=-1){ bos.write(buffer,0,temp); } //返回读取的数据 return bos.toString(); } catch (IOException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); }finally{ try { is.close(); bos.close(); } catch (IOException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } return null; } } 另一个是可以弹出toast import android.content.Context; import android.widget.Toast; public class ToastUtils { public static void show(Context ctx,String msg){ Toast.makeText(ctx, msg, 0).show(); } } 5,主营业务的介绍: protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //去除当前activity头title requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_splash); //初始化ui initUI(); //初始化方法 initData(); } 6,关于如何初始化ui private void initUI() { // TODO 自动生成的方法存根 tv_version_name = (TextView) findViewById(R.id.tv_version_name); } 找到相应控件 private void initData() { // TODO 自动生成的方法存根 //应用版本名称 tv_version_name.setText(getVersionName()); //获取本地服务版本号 myLockVersionCode = getVersionCode(); //获取服务器版本号(客户端发请求,服务器给相应(json,xml一般用的是json)) checkVersion(); } //返回版本号 private int getVersionCode() { // TODO 自动生成的方法存根 //1,包管理者对象packagemanager PackageManager pm=getPackageManager(); //2,从包的管理者对象中,获取指定包名的基本信息(版本名称,版本号,0代表基本信息) try { PackageInfo packageinfo=pm.getPackageInfo(getPackageName(), 0); return packageinfo.versionCode; } catch (NameNotFoundException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } return 0; } 这个方法可以 再来看checkVersion();方法 如果上网的话需要用到线程方面的知识 private void checkVersion() { new Thread(){ public void run(){ //Message message=new Message(); Message msg=Message.obtain(); long startTime=System.currentTimeMillis();//程序开始的时间 try { //封装url地址 URL url=new URL("http://192.168.1.104:8080/update74.json"); //开启一个地址 HttpURLConnection connection=(HttpURLConnection)url.openConnection(); //3,设置常见的请求参数(请求头) //请求超时 connection.setConnectTimeout(2000); //读取超时 connection.setReadTimeout(2000); //默认是get请求 //connection.setRequestMethod("POST"); //获取请求响应码 if(connection.getResponseCode()==200){ //5.以流的形式,将数据保存起来 InputStream is=connection.getInputStream(); //6.将流换成字符串(工具类封装) String json=StreamUtil.StreamToString(is); Log.i(tag, json);//打印日志 //7.json解析 JSONObject jsonObject=new JSONObject(json); String versionName=jsonObject.getString("versionName"); mversionDes = jsonObject.getString("versionDes"); String versionCode=jsonObject.getString("versionCode"); mdownloadUrl = jsonObject.getString("downloadUrl"); Log.i(tag, versionName); Log.i(tag, mversionDes); Log.i(tag, versionCode); Log.i(tag, mdownloadUrl); //8,比对版本号(服务器版本号,提示用户更新) if(myLockVersionCode <Integer.parseInt(versionCode)){ //提示用户更新,弹出对话框 msg.what=UPDATE_VERSION; }else{ //进入应用程序主界面 msg.what=ENTER_HOME; } } }catch (MalformedURLException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); msg.what=URL_ERROR; }catch (IOException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); msg.what=IO_ERROR; } catch (JSONException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); msg.what=JSON_ERROR; }finally{ //请求网络的时长超过四秒则不做处理 //请求小于四秒,强制让其睡眠四秒 long endTime=System.currentTimeMillis(); if(endTime-startTime<4000) { try { Thread.sleep(4000-(endTime-startTime)); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } mhandler.sendMessage(msg); } }; }.start(); 对上述信息进行相关的处理: private Handler mhandler=new Handler(){ public void handleMessage(android.os.Message msg){ switch(msg.what){ case UPDATE_VERSION: //弹出对话框,提示用户更新 showUpdateDialog();//弹出一个对话框,让我们进行更新 break; case ENTER_HOME: enterHome(); break; case IO_ERROR: ToastUtils.show(getApplicationContext(), "IO异常"); enterHome(); break; case URL_ERROR: ToastUtils.show(getApplicationContext(), "url异常"); enterHome(); break; case JSON_ERROR: ToastUtils.show(getApplicationContext(), "URL异常");//SplashActivity.this enterHome(); break; } } }; protected void showUpdateDialog() { // TODO 自动生成的方法存根 //对话框是依赖activity存在的 Builder builder = new AlertDialog.Builder(this);//必须用this,而不是getApplicationContext() builder.setIcon(R.drawable.ic_launcher); builder.setTitle("版本更新"); //设置描述内容 builder.setMessage(mversionDes);//这个描述内容见上文是由其发送过来的 //积极按钮,立即更新 builder.setPositiveButton("立即更新", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //下载apk,apk链接地址,downloadUrl downloadApk(); } });//创建两个按钮监听器 builder.setNegativeButton("稍后再说", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //取消对话框,进入主界面 enterHome(); } }); builder.show(); } 接下来是对文件进行下载 protected void downloadApk() { //apk下载链接地址,放置apk的所在路径 //1,判断sd卡是否可用,是否挂在上 if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ //2,获取sd卡路径 String path=Environment.getExternalStorageDirectory().getAbsolutePath() +File.separator+"mobilesafe73.apk"; //发送请求,获取sdk,并且添加到指定路径 HttpUtils httpUtils=new HttpUtils(); //发送请求,传递参数吧(下载应用放置的位置) httpUtils.download(mdownloadUrl, path,new RequestCallBack<File>() {//mdownloadUrl刚才所获得的下载的地址 @Override public void onSuccess(ResponseInfo<File> responseInfo) { Log.i(tag, "下载成功"); // TODO 自动生成的方法存根 File file=responseInfo.result; //提示用户安装 installAPK(file); } @Override public void onFailure(HttpException arg0, String arg1) { Log.i(tag, "下载失败"); // TODO 自动生成的方法存根 } @Override public void onStart() { // TODO 自动生成的方法存根 Log.i(tag, "开始下载"); super.onStart(); } @Override public void onLoading(long total, long current, boolean isUploading) { // TODO 自动生成的方法存根 Log.i(tag, "下载中........"); Log.i(tag, "total = "+total); Log.i(tag, "current = "+current); super.onLoading(total, current, isUploading); } }); } } //开始安装 protected void installAPK(File file) { // TODO 自动生成的方法存根 //系统应用界面,源码,安装apk入口 Intent intent = new Intent("android.intent.action.VIEW"); intent.addCategory("android.intent.category.DEFAULT"); /*//文件作为数据源 intent.setData(Uri.fromFile(file)); //设置安装的类型 intent.setType("application/vnd.android.package-archive");*/ intent.setDataAndType(Uri.fromFile(file),"application/vnd.android.package-archive"); // startActivity(intent); startActivityForResult(intent, 0); } //开启另一个界面 protected void enterHome() { Intent intent = new Intent(this,HomeActivity.class); startActivity(intent); //在开启一个新的界面后将导航界面关闭,因为导航界面只可见一次 finish(); } 本文转自眉间雪 51CTO博客,原文链接:http://blog.51cto.com/13348847/2046800,如需转载请自行联系原作者

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册