Sloppy's Blog


  • Home

  • About

  • Archives
Sloppy's Blog

IOS推送证书的不同语言的制作方法

Posted on 2016-10-18

PHP

导出私钥:

developer下载aps_development.cer

钥匙串 -> Keys -> 右边的私钥

1, openssl x509 -in aps_development.cer -inform der -out ErayOFFRemotionNotification.pem

2,openssl pkcs12 -nocerts -out ErayOFFRemotionNotificationKey.pem -in Certificates.p12

3,cat ErayOFFRemotionNotification.pem ErayOFFRemotionNotificationKey.pem > ErayOFFNotification.pem

Java

钥匙串 -> My Certificates 导出对应的Push证书 P12

NodeJS

钥匙串 -> My Certificates 导出对应的Push证书 cer格式

钥匙串 -> My Certificates 展开私钥 导出对应的Push证书 p12格式

1,openssl x509 -in cert.cer -inform DER -outform PEM -out cert.pem

2,openssl pkcs12 -in key.p12 -out key.pem -nodes

密码都输入:123456

Sloppy's Blog

NodeJS实现IOS中的APNS

Posted on 2016-10-17

生成证书

导出

打开钥匙串:
钥匙串 -> My Certificates 导出对应的Push证书 (cer格式)
钥匙串 -> My Certificates 展开私钥 导出对应的证书
密码输入:123456

生成PEM

Push证书 p12格式
终端输入
1,openssl x509 -in cert.cer -inform DER -outform PEM -out cert.pem
2,openssl pkcs12 -in key.p12 -out key.pem -nodes

NodeJS代码

安装apn

npm install apn

编写代码:

IOS注册省略

var apn = require("apn");

var tokens = ["e73447af823400987c05f31a2b5a0960a729ceaea9d772869f0f22eb463bea8c"];

var service = new apn.Provider({
  "cert": "push/cert.pem",
  "key": "push/key.pem",
  "passphrase":"123456",
  "production":false
});

var note = new apn.Notification({
  "alert":"末世战纪欢迎您的到来",
  "sound":"default"
});

// The topic is usually the bundle identifier of your application.
note.topic = "com.eray.off";
note.badge = 1;

console.log(`Sending: ${note.compile()} to ${tokens}`);
service.send(note, tokens).then( result => {
    console.log("sent:", result.sent.length);
    console.log("failed:", result.failed.length);
    console.log(result.failed);
});

// For one-shot notification tasks you may wish to shutdown the connection
// after everything is sent, but only call shutdown if you need your 
// application to terminate.
service.shutdown();
Sloppy's Blog

std::sort元素相等导致crash

Posted on 2016-10-17

最近项目里碰到一个奇怪的问题。在某些特定的服务器上,执行某段代码,会突然Crash,代码没有动过,查了半天。原来是std::sort搞出的问题,因为之前返回的元素从来没有相等的情况,所以没有出现过Crash,STD的sort,如果出现两个相等的元素返回true,会导致越界行为

std::vector list = {2,1,1,3,};
std::sort(list.begin(), list.end(), [](int a,int b){
    if (a == b){// 这地方
        return true;
    }
    return a > b;
});
Sloppy's Blog

NodeJS验证IOSIAP充值

Posted on 2016-10-12

对于很多前端开发者来说,经常需要自己写一些测试验证程序,当然很多的前端开发者,都会PHP,Java,写个简单的服务器测试程序也很简单。但是苦于有的同学,没有这些经验,也没有这些环境,而NodeJS也是前端开发者必备的环境之一,同时也可以很好的开发服务器程序,当然现在很多成熟的游戏都是基于NodeJS的,前几开在做IOS的内购测试。需要在服务端连接苹果服务器进行验证。写了一个简单的测试程序,记下来。备以后查找

/**
* @brief 跟苹果服务充值服务器进行检验
* @param receiptData IOS充值回调的transaction.transactionReceipt base64Encoding
* @param responder 验证回调
* @param inReview 是否处于审核阶段
*/ 
var verifyReceipt = function(receiptData, responder,inReview){
  var receiptEnvelope = {"receipt-data": receiptData};
  var receiptEnvelopeStr = JSON.stringify(receiptEnvelope);
  var options = {
      host: inReview?'sandbox.itunes.apple.com':'buy.itunes.apple.com',
      port: 443,
      path: '/verifyReceipt',
      method: 'POST',
      headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          'Content-Length': Buffer.byteLength(receiptEnvelopeStr)
      }
  };

  var req = https.request(options, function(res) {
      var _data='';
      res.setEncoding('utf8');
      res.on('data', function (chunk) {
          _data += chunk;
      });
      res.on('end', function () {
          console.log("body: " + _data);
          responder(_data);
      });
  });

  req.write(receiptEnvelopeStr);
  req.end();
};

客户端服务端代码参考:下载

Sloppy's Blog

AndroidJava调用C++,及C++调用Java

Posted on 2016-09-22

正常的Android开发过程中,难免会出现需要大量的计算,这时候,我们可能就会想到,需要提高计算的速度,这里可能想到利用c/C++,来提高运算速度,那我们这时候,就需要接触到这方面的相关知识了,下面我们作一下简单的实例测试,需要用的工具,包括Android SDK,NDK

创建项目

首先我们创建一个简单的Android项目,然后在layout布局文件上,加一个简单的textview,取名ID为,labelTxt,设置字内容为HelloAndroid.在MainActivity里定义一个方法方法,同时添加载入SO文件的逻辑,内容如下 :

1
2
3
4
public native String stringFromJNI();
static{
System.loadLibrary("jni-test"); // 为什么叫jni-test,跟后面的MK文件内容配置
}

在onCreate方法里添加如下内容:

1
2
3
4
5
String str = "Form Assets so:"+stringFromJNI();
TextView txt = (TextView)this.findViewById(R.id.labelTxt);
if(txt!=null){
txt.setText(str);
}

Java调用C++

这里,我自己手动编写CPP(com_nikoer_helloandroidapp_MainActivity.cpp)文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <jni.h>
#include <android/log.h>
#include <string>
#include "JniHelper.h"
#define LOG_TAG "MAIN"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
extern "C"
{
JNIEXPORT jstring JNICALL Java_com_nikoer_helloandroidapp_MainActivity_stringFromJNI(JNIEnv* env, jobject thiz){
std::string t="JNI Value";
return env->NewStringUTF(t.c_str());
}
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
LOGD("JNI_OnLoad");
return JNI_VERSION_1_4;
}
}

这里我用的的是C++编译,所以用到了extern “c”

在项目根目录下建一个jni目录,把CPP文件复制进去,在jni目录下编写Android.mk文件,跟Application.mk文件,
Android.mk:

1
2
3
4
5
6
7
8
9
10
11
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_LDLIBS := -landroid
LOCAL_LDLIBS += -llog
LOCAL_MODULE := jni-test
LOCAL_SRC_FILES := com_nikoer_helloandroidapp_MainActivity.cpp
include $(BUILD_SHARED_LIBRARY)

Application.mk:

1
2
3
4
5
6
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -DCC_ENABLE_CHIPMUNK_INTEGRATION=1 -std=c++11 -fsigned-char
APP_LDFLAGS := -latomic
APP_ABI := armeabi

在jni目录下,运行命令行,输入:ndk-build (当前前掉得设置ndk的环境变量,才可以运行ndk-build命令),用eclipse刷新项目,运行目录。是不是发布HelloWorld变成了JNI Value.

C++调用Java

这里我们封闭一个类出来JniHelper,内容如下:
JniHelper.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#pragma once
#include <jni.h>
typedef struct JniMethodInfo_
{
JNIEnv * env;
jclass classID;
jmethodID methodID;
} JniMethodInfo;
class JniHelper{
public:
static void setJavaVM(JavaVM *vm);
static JNIEnv* getEnv();
static bool getStaticMethodInfo(JniMethodInfo &methodinfo, const char *className, const char *methodName,const char *paramCode);
private:
static JavaVM *pvm;
};

JniHelper.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include "JniHelper.h"
#include <android/log.h>
#define LOG_TAG "JniHelper"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
JavaVM* JniHelper::pvm=nullptr;
void JniHelper::setJavaVM(JavaVM *vm){
pvm = vm;
}
JNIEnv* JniHelper::getEnv(){
JNIEnv* env=nullptr;
pvm->GetEnv((void**)&env,JNI_VERSION_1_4);
return env;
}
bool JniHelper::getStaticMethodInfo(JniMethodInfo &methodinfo, const char *className,const char *methodName, const char *paramCode) {
if ((nullptr == className) ||
(nullptr == methodName) ||
(nullptr == paramCode)) {
return false;
}
JNIEnv *env = JniHelper::getEnv();
if (!env) {
LOGE("Failed to get JNIEnv");
return false;
}
jclass classID = env->FindClass(className);
if (! classID) {
LOGE("Failed to find class %s", className);
env->ExceptionClear();
return false;
}
jmethodID methodID = env->GetStaticMethodID(classID, methodName, paramCode);
if (! methodID) {
LOGE("Failed to find static method id of %s", methodName);
env->ExceptionClear();
return false;
}
methodinfo.classID = classID;
methodinfo.env = env;
methodinfo.methodID = methodID;
return true;
}

修改入口文件com_nikoer_helloandroidapp_MainActivity.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
extern "C"
{
JNIEXPORT jstring JNICALL Java_com_nikoer_helloandroidapp_MainActivity_stringFromJNI(JNIEnv* env, jobject thiz){
std::string t="JNI Value";
// 开始由C++ 调用Java
JniMethodInfo minfo;
bool result = JniHelper::getStaticMethodInfo(minfo,"com/nikoer/helloandroidapp/MainActivity","getTime","()Ljava/lang/String;");
if(result){
jstring jstr = (jstring)minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID);
t = "JNI:"+std::string((char*)env->GetStringUTFChars(jstr, 0));
}
return env->NewStringUTF(t.c_str());
}
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
LOGD("JNI_OnLoad");
JniHelper::setJavaVM(vm);
return JNI_VERSION_1_4;
}
}

修改Android.mk:

1
2
3
4
5
6
7
8
9
10
11
12
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_LDLIBS := -landroid
LOCAL_LDLIBS += -llog
LOCAL_MODULE := jni-test
LOCAL_SRC_FILES := com_nikoer_helloandroidapp_MainActivity.cpp \
JniHelper.cpp
include $(BUILD_SHARED_LIBRARY)

修改JavaActivity,添加如下方法

1
2
3
public static String getTime() {
return String.valueOf(System.currentTimeMillis());
}

运行:ndk-build,再用Eclipse刷新项目,运行项目,是不是变成时间字符串了

源文件参考:下载

Sloppy's Blog

利用xcodeproj实现IOS项目的自动生成

Posted on 2016-09-18

背景

做Cocos2d-x的游戏开发者都知道,大部分开发团队都是Windows VS开发项目(壕团队除外),我们在编译Android项目时,都需要重新生成jni/Android.mk文件,由于该文件是一个简单的文本文件,我们可以随便通过任何脚本,譬如Python,在每次编译前根据模板MK文件生成Android.mk文件,很方便,然后在自动化编译IOS项目时,我们就有点麻烦了,每次都需要重新配置下xcodeproj的项目文件,然后最后发布可能还需要发布证书。之前问了许多朋友都是由某个程序员进行发布前的手动添加,太麻烦,而且不智能,容易出错。那有没有象Android一样的方法呢?答案肯定是有了。经过一番摸索,由于之前没有接触过Ruby,而比较成熟的就是CocoaPods的xcodeproj开发项目,该项目是ruby开发。

进行

下面进行一系统软件的安装:

  • 安装ruby
    https://www.ruby-lang.org/ 当然mac还可以brew install ruby这样安装
  • 安装xcodeproj(可能需要sudo)
    gem install xcodeproj
  • 由于用到ini配置文件,安装inifile
    gem install inifile

代码尝试

关键代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
project = Xcodeproj::Project.open($PROJECT_PATH)
project.targets.each do |target|
if target.name==$TARGET_NAME
group = project.main_group
group.set_source_tree('SOURCE_ROOT')
#get_file_list(CLASS_PATH)
generateSubGroup(target,group,$CLASS_PATH,"#{$SOURCE_FOLDER_NAME}","../#{$SOURCE_FOLDER_NAME}/")
#sdkGroup = group.find_subpath(File.join('sdk','ios'), true)
#file_ref = sdkGroup.new_reference("../Classes/sdk/SDK.cpp")
#file_ref = sdkGroup.new_reference("../Classes/sdk/SDK.hpp")
#target.add_file_references([file_ref])
end
end
project.save()

代码参考:点击下载

Sloppy's Blog

c可变参数使用

Posted on 2016-09-06

在C语言编程中有时会遇到一些参数个数可变的函数,例如printf(),scanf()函数,其函数原型为:
int printf(const char format,…),int scanf(const char format,…);
它除了有一个参数format固定以外,后面跟着的参数的个数和类型是可变的(用三个点“…”做参数占位符),实际调用时可以有以下的形式: printf(“%d”,i); printf(“%d,%c”,i,j);

下面可以自己实现一个可变参数的实例:

1
2
3
4
5
6
7
8
9
10
11
12
void HelloWorld::testParam(int mode, ...) {
va_list ap;
va_start(ap, mode);
int arg;
while(true){
arg = va_arg(ap, int);
if (arg == -1)
break;
CCLOG("mode:%d", arg);
}
va_end(ap);
}

Sloppy's Blog

回顾一些二进制算法

Posted on 2016-08-29

&按位与

按位与运算 按位与运算符”&”是双目运算符。其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结果位才为1 ,否则为0。参与运算的数以补码方式出现。
例如:9&5可写算式如下: 00001001 (9的二进制补码)&00000101 (5的二进制补码) 00000001 (1的二进制补码)可见9&5=1。
按位与运算通常用来对某些位清0或保留某些位。例如把a 的高八位清 0 , 保留低八位, 可作 a&255 运算 ( 255 的二进制数为
0000000011111111)。

1
2
3
4
5
6
int main(){
int a=9,b=5,c;
c=a&b;
printf("a=%dnb=%dnc=%dn",a,b,c);
return 0;
}

算法举例,求一个十六制的RGB颜色值:

1
2
3
4
int c = 0xFFFFFF;
int r = c >> 16;
int g = c >> 8 & 0xFF
int b = c & 0xFF;

|按位或

按位或运算 按位或运算符“|”是双目运算符。其功能是参与运算的两数各对应的二进位相或。只要对应的二个二进位有一个为1时,结果位就为1。参与运算的两个数均以补码出现。
例如:9|5可写算式如下: 00001001|00000101
00001101 (十进制为13)可见9|5=13

1
2
3
4
5
6
int main(){
int a=9,b=5,c;
c=a|b;
printf("a=%dnb=%dnc=%dn",a,b,c);
return 0;
}

算法举例:已经RGB的值,求十六进制的RGB值

1
2
3
4
int r = 255;
int g = 255;
int b = 255;
int c = r << 16 | g << 8 | b;

^ 按位异或

按位异或运算 按位异或运算符“^”是双目运算符。其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。参与运算数仍以补码出现,例如9^5可写成算式如下: 00001001^00000101 00001100 (十进制为12)

1
2
3
4
5
6
int main(){
int a=9;
a=a^15;
printf("a=%dn",a);
return 0;
}

算法举例:不产生临时变量,交换两个变量的值

1
2
3
4
5
int a = 1;
int b = 2;
a = a^b;
b = b^a;
a = a^b;

Sloppy's Blog

C++的构造与Copy构造

Posted on 2016-08-22

在C++中,自定义类,在把类的一个实体赋值给另外一个同类型的变量对象是,系统会自动完成构造函数的,即使我们没有提供默认的构造函数,因为系统会自动产生一个构造函数。譬如如下的定义与使用:

struct TestData
{
    int age;
    TestData(int g) {
        age = g;
    }
    // 系统产生的默认构造函数跟这个是一样的
    TestData(TestData &c) {
        // 注释掉这个试试,下面的输出会产生一个奇怪的输出
        age = c.age;
    }
    TestData(const TestData &c) {
        age = c.age;
    }
    ~TestData() {

    }
};

使用:
TestData aa(99);
TestData bb = aa;
CCLOG(“TestData:%d”,bb.age);

上面的定义Copy构造函数,跟不定义都没有关系。但是如果类内有通过在堆上产生的数据,在析构函数体内是需要delete的,此时如果用赋值的方法,给另外一对象,因为在堆上生成的内存,此时只有一份内存,如果产生两次析构。会使程序产生异常的。因此,我们此时需要自定义Copy构造函数了。

struct TestData
{
    Node* node;
    TestData(int g) {
        age = g;
        node = new Node();
    }
    // 系统产生的默认构造函数跟这个是一样的
    TestData(TestData &c) {
        age = c.age;
        //node = c.node;
        node = new Node();
    }
    ~TestData() {
        delete = node;
    }
};

,还是如上的测试方法。如果你把自定义的copy构造函数注释掉试试。

Sloppy's Blog

cocos2d-x如果让c++执行js回调

Posted on 2016-08-19

此文章接:点击查看绑定C++给JS调用 这篇文章而来.

Cocos2d-x JS项目中JS调用C++,相对比较简单,在前一篇文章也做了说明。主要是绑定C++给JS调用。相对简单,那昨天看到论坛里好多朋友一直在讨论C++调用JS的问题,好象都有一些奇怪的问题,今天做了一个测试DEMO。下面分几点来看一下。

改造之前的C++类(Eraylayer)

新增一个Delegate类,为ErayLayer添加设置Delegate类,ErayLayer头文件如下:

class ErayDelegate:public cocos2d::Ref {
public:
    virtual void onClick(const std::string& value) {};
    virtual ~ErayDelegate() {};
};

class ErayLayer :public cocos2d::Layer {
public:
    ErayLayer();
    ~ErayLayer();
    virtual bool init();
    CREATE_FUNC(ErayLayer);
    void setDelegate(ErayDelegate* _delegate);
private:
    ErayDelegate* m_pDelegate;
};

CPP文件如下:

ErayLayer::ErayLayer() {
    m_pDelegate = nullptr;
}
ErayLayer::~ErayLayer() {
    CC_SAFE_RELEASE(m_pDelegate);
}
bool ErayLayer::init() {
    if (!Layer::init()) {
        return false;
    }
    ImageView* image = ImageView::create();
    image->loadTexture("res/diamond3.png");
    image->setTouchEnabled(true);
    image->addTouchEventListener([=](Ref *pSender, ui::Widget::TouchEventType type) {
        if (type != ui::Widget::TouchEventType::ENDED)
            return;
        if (m_pDelegate) {
            m_pDelegate->onClick("call from cpp");
        }
        CCLOG("click on Image");
    });
    image->setPosition(Vec2(300.0f, 300.0f));
    addChild(image);
    return true;
}
/**
* @brief 设置代理执行类
*/
void ErayLayer::setDelegate(ErayDelegate* _delegate) {
    if (_delegate) {
        m_pDelegate = _delegate;
        m_pDelegate->retain();
    }
}

新增jsb_coolexp_manual.hpp,jsb_coolexp_manual.cpp,主要代码如下:

〈pre>
class JSB_ErayDelegate :public ErayDelegate {
public:
JSB_ErayDelegate() {

}
virtual void onClick(const std::string& value) override {
    // 执行代理的方法
    JSContext *cx = ScriptingCore::getInstance()->getGlobalContext();
    jsval arg = std_string_to_jsval(cx, value);
    JS::RootedValue delegateVal(cx, _JSDelegate);
    ScriptingCore::getInstance()->executeFunctionWithOwner(delegateVal, "onClick", 1, &arg);

    // 调用一个全部的对象的方法
    JSContext * context = ScriptingCore::getInstance()->getGlobalContext();
    JS::RootedObject object(context, ScriptingCore::getInstance()->getGlobalObject());
    JS::RootedValue owner(context);
    jsval arg1 = INT_TO_JSVAL(1001);

    JS_GetProperty(context, object, "Config", &owner);
    ScriptingCore::getInstance()->executeFunctionWithOwner(owner, "sendNumber", 1, &arg1);
}
void setJSDelegate(JS::HandleValue pJSDelegate)
{
    _JSDelegate = pJSDelegate;
}

private:
JS::Heap _JSDelegate;
};
static bool jsb_ErayLayer_setJSHandler(JSContext cx, uint32_t argc, jsval vp) {
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
JS::RootedObject obj(cx, args.thisv().toObjectOrNull());
js_proxy_t proxy = jsb_get_js_proxy(obj);
ErayLayer
cobj = (ErayLayer )(proxy ? proxy->ptr : NULL);
JSB_PRECONDITION2(cobj, cx, false, “Invalid Native Object”);
if (argc == 1)
{
// save the delegate
JSB_ErayDelegate
nativeDelegate = new (std::nothrow) JSB_ErayDelegate();
nativeDelegate->setJSDelegate(args.get(0));
cobj->setDelegate(nativeDelegate);
args.rval().setUndefined();
nativeDelegate->release();
return true;
}
JS_ReportError(cx, “wrong number of arguments: %d, was expecting %d”, argc, 1);
return false;
}

extern JSObject jsb_ErayLayer_prototype;
void register_all_coolexp_manual(JSContext
cx, JS::HandleObject global)
{
JS::RootedObject proto(cx, jsb_ErayLayer_prototype);
JS_DefineFunction(cx, proto, “setJSDelegate”, jsb_ErayLayer_setJSHandler, 1, JSPROP_ENUMERATE | JSPROP_PERMANENT);
}

JS文件内容:

var erayLayer = ErayLayer.create();
this.addChild(erayLayer);
erayLayer.setJSDelegate({
    "onClick":function(value){
        cc.log("onClick:%s",value);
    }
});

// 写在JS顶层
var Config = Config || {};

Config.sendNumber = function(num)
{
    cc.log("From javascript: " + num);
};

运行点击场景上的图片,看打印输出

参考文件:点击查看

1234…6
Sloppy

Sloppy

54 posts
7 tags
© 2017 Sloppy
Powered by Hexo
Theme - NexT.Muse