IOS上架流程

本教程使用HBuilder打包APP

1.登录苹果开发者中心 Apple Developer
12FF1F2B-4286-4B3E-9BBB-B6370F381F52

2.点击 Certificates, Identifiers & Profiles
944386B1-4A6F-4C54-8884-F994C4F2023A

3.创建App Id
8D4BA763-0146-4EEA-A0CA-6012549E6BF9
download

4.创建Certificate
19E41D90-A485-451D-BB1B-28E6604FE8DA
download -7-
download -1-

5.创建本地证书
84138649-5D5C-461D-A198-771196CB16A4

打开 Keychain Access 程序,点击电脑左上角的Keychain Access => Certificate Assistant => Request a Certificate From a Certificate Authority,中文系统的话就是钥匙串访问 => 证书助理 => 从证书颁发机构请求证书
C1264B8B-E387-410D-8512-866E3C4FFC10

输入邮箱地址、名字,选择保存到本地
0CB388C9-6689-4699-853E-18C663F8C605

6.回到苹果开发者网站,继续刚才的步骤
download -2-
9AEA91CD-A52D-45F0-854D-C92F5B0A1F43

7.双击下载的.cer文件,导入到电脑的Keychain Access中,然后右键导出成.p12文件,导出时需要设置.p12文件的密码
66C80D2D-F6F6-4B0A-97B8-5A6794056BDA
F8E74666-B49E-45F6-95D2-2E1345C6492F

8.创建描述文件
download -3-
download -4-
download -5-
download -6-
download -8-
download -9-

9.通过HBuilder打包上线.ipa文件
D715AAFB-0268-4D37-8D81-CF6B3ADE7D20
83B5600D-DF09-44C9-8665-17AAAB0F00AB

10.通过HBuilder打包成功之后,就需要通过 Application Loader 上传.ipa文件
95529EC8-0629-4A43-93EE-1787431648E2

登录
0183B731-7355-476A-9402-AAB97FDA64BE

在上传之前,需要在此iTunes Connect录入APP信息

2017/11/25 posted in  其他

用TypeScript来写推箱子游戏

先介绍下TypeScript

TypeScript 是JavaScript类型的超集,可以编译成纯JavaScript,由微软开发。允许JavaScript开发者在开发JavaScript应用程序时使用高效的开发工具和常用操作比如静态检查和代码重构。

讲讲游戏

推箱子游戏,在一个狭小的仓库中,要求把木箱放到指定的位置,稍不小心就会出现箱子无法移动或者通道被堵住的情况,所以需要巧妙的利用有限的空间和通道,合理安排移动的次序和位置,才能顺利的完成任务。

使用的技术栈

Vue —用来渲染游戏
TypeScript —实现游戏逻辑

地图
游戏中的地图,我使用的是number[][]一个二维数组来表示。一维数组的下标表示坐标系的Y轴,二维数组的下标表示坐标系的X轴,二维数组的值是改坐标点表示的元素角色,根据不同的角色去渲染。

/**
* 地图坐标点角色
*/
enum Role {
    /**
     * 空白
     */
    Blank,
    /**
     * 墙
     */
    Wall,
    /**
     * 小人
     */
    People,
    /**
     * 站在点上小人
     */
    PeopleDot,
    /**
     * 箱子
     */
    Chest,
    /**
     * 箱子点
     */
    Dot,
    /**
     * 到点的箱子
     */
    ChestDot
}

代码中,我用一个Map类封装保存当前地图的状态和一些常用方法,比如当前关卡的层级、所有关卡的初始地图数据。

界面用vue去渲染

<template v-for="(yItem,y) in Map">
<ul>
    <li v-for="(xItem,x) in yItem" @click="SetRole(y,x)">
        <div :class="getRoleClass(xItem)" style="width:100%;height:100%;" :title="xItem" :key="y + '-' + x"></div>
    </li>
</ul>
<div style="clear:both;"></div>
</template>

小人
小人需要上、下、左、右的四处移动,并且移动之前还需要判断,如果是墙就不能移动;如果是箱子,就需要推动箱子。这也是推箱子游戏中核心的功能逻辑。所以在代码中,用一个People类来封装,保存小人当前的坐标和移动操作。

class People {
    private currentCoord: Coord;
    constructor(coord: Coord) {
        this.currentCoord = coord;
    }

    private getNewCoord(oldCoord: Coord, potion: MovePotion): Coord {
        let newCoord: Coord = {
            Y: oldCoord.Y,
            X: oldCoord.X
        }
        switch (potion) {
            case MovePotion.Up:
                newCoord.Y--;
                break;
            case MovePotion.Right:
                newCoord.X++;
                break;
            case MovePotion.Down:
                newCoord.Y++;
                break;
            case MovePotion.Left:
                newCoord.X--;
                break;
        }

        return newCoord;
    }

    setCoord(coord: Coord) {
        this.currentCoord.Y = coord.Y;
        this.currentCoord.X = coord.X;
    }

    /**
     * 移动小人
     * @param potion 移动方向
     */
    move(potion: MovePotion) {
        let peopleNewCoord: Coord = this.getNewCoord(this.currentCoord, potion);
        let currentCoordRole: Role = game.getCoordRole(this.currentCoord);
        let newCoordRole: Role = game.getCoordRole(peopleNewCoord);
        if (!(newCoordRole == Role.Blank || newCoordRole == Role.Chest || newCoordRole == Role.Dot || newCoordRole == Role.ChestDot))
            return;

        let updateCurrentCoord = () => {
            this.currentCoord.Y = peopleNewCoord.Y;
            this.currentCoord.X = peopleNewCoord.X;
            game.addPace();
        }

        if (newCoordRole == Role.Blank) {
            game.setCoordRole(peopleNewCoord, Role.People);
            game.setCoordRole(this.currentCoord, currentCoordRole == Role.PeopleDot ? Role.Dot : Role.Blank);
            updateCurrentCoord();
        } else if (newCoordRole == Role.Dot) {
            game.setCoordRole(peopleNewCoord, Role.PeopleDot);
            game.setCoordRole(this.currentCoord, currentCoordRole == Role.PeopleDot ? Role.Dot : Role.Blank);
            updateCurrentCoord();
        } else if (newCoordRole == Role.Chest || newCoordRole == Role.ChestDot) {
            let newChestCoord: Coord = this.getNewCoord(peopleNewCoord, potion);
            let newChestCoordRole: Role = game.getCoordRole(newChestCoord);
            if (newChestCoordRole == Role.Wall || newChestCoordRole == Role.ChestDot || newChestCoordRole == Role.Chest)
                return;

            game.setCoordRole(newChestCoord, newChestCoordRole == Role.Dot ? Role.ChestDot : Role.Chest);
            game.setCoordRole(peopleNewCoord, newCoordRole == Role.ChestDot ? Role.PeopleDot : Role.People);
            game.setCoordRole(this.currentCoord, currentCoordRole == Role.PeopleDot ? Role.Dot : Role.Blank);
            updateCurrentCoord();
        }

        game.verifySuccess();
    }
}

游戏交互
最后用一个Game类来封装游戏的渲染、交互等,用Vue给方向键绑定点击事件。

写在最后
总的来说,用TypeScript来开发JavaScript项目,是一个不错的选择,既有了类型检查,又不会失去JavaScript语言的灵活性。在加上VS Code IDE的智能感知,开发起来方便快速。

GitHub
演示地址

2017/11/25 posted in  网站开发

谷歌扩展插件分享

推荐几款我自己用着不错的谷歌扩展插件

  • 一键管理所有扩展 谷歌扩展插件装的多了,会占用浏览器内存,不是所有插件都需要一直开着的,有了这款插件就可以很方便的管理那些插件
  • Charset 现在新版的谷歌浏览器已经没有了可以随意切换网页编码的功能了,所以现在就需要这款插件了
  • Auto-Translate 基于谷歌翻译的一款可以划词翻译的扩展
  • Screen Video Recorder 可以网页截图,截一块或者一整个网页都可以
  • ColorPick Eyedropper 获取网页上颜色的值
  • Holmes 方便快速检索谷歌书签,只需要在浏览器地址栏输入星号(*),然后按tab键就可以搜索了
  • Insight.io for Github 浏览器Github项目时,很方便的一款插件
  • IP 域国家国旗 可以显示当前浏览网页的IP和国家
  • JavaScript Errors Notifier 可以让谷歌浏览器像IE浏览器一样,在有Js报错时,在页面右下角显示提示
  • JSON-handle 美化JSON数据
  • KeyCodez 快速展示键盘按键对应的数字
  • Page load time 显示网页打开的时间
  • Postman 方便调试异步接口
  • Remove Google Redirection 谷歌搜索展示的结果会经过一层跳转,这个扩展就是去掉这层跳转,直接展示原始地址
  • Request Maker 方便调试异步接口
  • The QR Code Extension 直接生成当前网页的二维码
  • WEB前端助手 看名字就知道干什么的了,用的比较多的就是字符串编解码和JSON格式化了
  • 掘金 可以在新标签页展示技术内容
2017/11/25 posted in  其他

阿里云短信平台发送短信开发

官方文档:
短信发送API
短信业务规则

一、开发准备

下载SDK
申请秘钥
申请短信签名
添加短信模板

二、.NET版发送短信

需要引入SDK中的aliyun-net-sdk-core.dll和aliyun-net-sdk-dysmsapi.dll

using Aliyun.Acs.Core;
using Aliyun.Acs.Core.Exceptions;
using Aliyun.Acs.Core.Profile;
using Aliyun.Acs.Dysmsapi.Model.V20170525;

namespace Whir.SMS.AliYun
{
    public class SendSMS
    {
        private readonly string _sign;
        private readonly string _accessKeyId;
        private readonly string _accessKeySecret;
        /// <summary>
        /// </summary>
        /// <param name="sign">签名</param>
        /// <param name="accessKeyId">Access Key Id</param>
        /// <param name="accessKeySecret">Access Key Secret</param>
        public SendSMS(string sign, string accessKeyId, string accessKeySecret)
        {
            _sign = sign;
            _accessKeyId = accessKeyId;
            _accessKeySecret = accessKeySecret;
        }

        /// <summary>
        /// </summary>
        /// <param name="templateCode">短息模板Code</param>
        /// <param name="phone">手机号</param>
        /// <param name="content">内容键值对,{ 占位符名称:内容 }</param>
        /// <param name="outId">外部流水扩展字段,回执消息中带回</param>
        /// <returns></returns>
        public SendResult Send(string templateCode, string phone, Dictionary<string, string> content, string outId = "")
        {
            String product = "Dysmsapi";//短信API产品名称
            String domain = "dysmsapi.aliyuncs.com";//短信API产品域名
            String accessKeyId = _accessKeyId;//你的accessKeyId
            String accessKeySecret = _accessKeySecret;//你的accessKeySecret

            IClientProfile profile = DefaultProfile.GetProfile("cn-hangzhou", accessKeyId, accessKeySecret);

            DefaultProfile.AddEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
            IAcsClient acsClient = new DefaultAcsClient(profile);
            SendSmsRequest request = new SendSmsRequest();
            try
            {
                //必填:待发送手机号。支持以逗号分隔的形式进行批量调用,批量上限为20个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式
                request.PhoneNumbers = phone;
                //必填:短信签名-可在短信控制台中找到
                request.SignName = _sign;
                //必填:短信模板-可在短信控制台中找到
                request.TemplateCode = templateCode;
                //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
                request.TemplateParam = content != null && content.Keys.Count > 0 ? content.ToJson() : "";
                //可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
                request.OutId = outId;
                //请求失败这里会抛ClientException异常
                SendSmsResponse sendSmsResponse = acsClient.GetAcsResponse(request);

                if (sendSmsResponse.Code.Equals("OK"))
                {
                    return new SendResult
                    {
                        IsSuccess = true,
                        ResponseData = sendSmsResponse.BizId
                    };
                }

                return new SendResult
                {
                    IsSuccess = false,
                    Message = sendSmsResponse.Message
                };
            }
            catch (ServerException e)
            {
                return new SendResult
                {
                    IsSuccess = false,
                    Message = e.Message
                };
            }
            catch (ClientException e)
            {
                return new SendResult
                {
                    IsSuccess = false,
                    Message = e.Message
                };
            }
        }
    }
}
2017/11/25 posted in  网站开发

Window 部署 Nodejs

  1. 安装 node.js,用express的再安装express
  2. 安装iis的url重写工具 URL Rewrite : The Official Microsoft IIS Site
  3. 安装iis上的反向代理工具 Application Request Routing
  4. Node 网站部署为8080端口
  5. 添加IIS网站,绑定为80端口
  6. 添加反向代理

    2DC9A538-DA16-4A7E-985E-82A2C25B549F

  7. 利用pm2启动nodejs网站

    # pm2 start index.js
    # pm2 start index.js --name my-api   #my-api为PM2进程名称
    # pm2 start index.js -i 0           #根据CPU核数启动进程个数
    # pm2 start index.js --watch   #实时监控的方式启动,当index.js文件有变动时,pm2会自动reload
    
  8. 访问网站

2017/11/25 posted in  NodeJs