weex插件开发与发布(以个推推送为例),看完少踩几天的坑

吐槽:weex 文档真心太少,特别是自定义插件,几乎为零,希望这篇文档对你有帮助

1.修改plugin模板文件

找到 weex plugin 命令执行代码
~/.xtoolkit/node_modules/weexpack/bin/weexpack-plugin.js
会发现最终模板文件在 generator-weex-plugin 里面

  1. node_modules/generator-weex-plugin/../templates 下面js upperCamelCaseName 都改为 lowerCamelCaseName

  2. package.json里面的copy:examples 改为

"rm -rf ./playground/android/app/src/main/assets/* && cp -vrf ./examples/build/* ./playground/android/app/src/main/assets/ &&rm -rf ./playground/ios/bundlejs/* && cp -vrf ./examples/build/* ./playground/ios/bundlejs/"

  1. playground/android/gradle-wrapper.properties 改为4.1.

  2. android/libary下面的build.gradle defaultConfig 新增

     defaultConfig {
         ...
         javaCompileOptions {
             annotationProcessorOptions {
                 includeCompileClasspath true
             }
         }
         ...
     }
    
  3. playground/android/setting.gradle 将libary改成module名称

    include ":getuipush"
    project (':getuipush').projectDir = new File("../../android/library")
    

    app/build.gradle文件中修改为:

    compile project(path: ':getuipush')
    
这么多坑,燃根烟消消愁~ 😂😂

2. weex plugin create getui-push

  • 生成的目录结构如下

     ├── android(Android插件工程)
     │    ├── buid.gradle(android发布文件)
     ├── ios(ios插件工程)
     ├── js(h5插件工程)
     ├── examples(例子,开发者用来测试问题)
     │    ├── build
     │    └── index.we
     ├── playground(测试实例,写好的module在各端做测试使用)
     │    ├── android(demo)
     │    ├── ios(demo)
     │    └── browser(demo)          
     ├── ****.podspec(ios发布文件)
     ├── package.json(js发布文件)
     ├── README.md
    
    最终js代码 (几行js代码 ios和android的推送就轻轻松松搞定)
    const plugin = weex.requireModule('getuiPush');
    
    plugin.initPush({
        appId:'appId',
        appKey:'appKey',
        appSecret:'appSecret',
    });
    
    plugin.onRegisterClient(function (clientId) {
        console.log('js 收到' + clientId);
    });
    
    plugin.onReceivePayloadData(function (payloadData) {
        console.log('js 收到' + JSON.stringify(payloadData));
    });
    

3.编写ios插件 代码 (以weex-getui-push 为例)

weex 会自动在ios/Sources目录下生成两个GetuiPushModule.h(头文件) GetuiPushModule.m(源文件)

  1. 配置个推sdk

    • 在 根目录下的 GetuiPush.podspec 加入
      s.dependency "GTSDK"
    • 在 ios目录下的 Podfile 加入
      pod 'GTSDK', '2.0.0.0-noidfa'
    • 切入到playground/ios 目录 执行
      pod update
  2. 初始化个推

    • js结构为:initPush(options)

      我们需要现在 GetuiPushModule.h 头文件里面声明 initGeTui这个方法

         //添加宏WX_EXPORT_METHOD, 它可以被weex识别
         WX_EXPORT_METHOD(@selector(initPush:))
      
        //js 初始化个推
        - (void)initPush:(NSDictionary *)options
        {
            [self startSdkWith:options[@"appId"] appKey:options[@"appKey"] appSecret:options[@"appSecret"]];
            
            //[2]:注册APNS
            [self registerRemoteNotification];
            
            //打开app时候,消除掉badge
            [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
            
            if ([[UIDevice currentDevice].systemVersion doubleValue] >= 8.0) {
                
                // iOS8以后 本地通知必须注册(获取权限)
                UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil];
                
                [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
            }
            //[2-EXT]: 获取启动时收到的APN数据
        }
      
  3. 当个推推送消息到客户端的时候需要告诉到js代码

    • js结构为:
      plugin.onReceivePayloadData(callback)

    • 声明变量来接收callback

        @interface GetuiPushModule()
            @property(nonatomic,copy)WXModuleKeepAliveCallback onRegisterClientCallBack;
      
            @property(nonatomic,copy)WXModuleKeepAliveCallback onReceivePayloadDataCallBack;
        
        @end
      
    • 同样在 GetuiPushModule.h声明 onReceivePayloadData这个方法

        - (void)onRegisterClient:(WXModuleKeepAliveCallback)callback
        {
            self.onRegisterClientCallBack = callback;
        }
        - (void)onReceivePayloadData:(WXModuleKeepAliveCallback)callback
        {
            self.onReceivePayloadDataCallBack = callback;
        }
      
    • 当个推推送消息到客户端,ios会执行GeTuiSdkDidReceivePayloadData,我们可以在该方法里通过以下代码回调js代码

        -(void)GeTuiSdkDidReceivePayloadData:(NSData *)payloadData andTaskId:(NSString *)taskId andMsgId:(NSString *)msgId andOffLine:(BOOL)offLine fromGtAppId:(NSString *)appId {
            NSDictionary *msgDict = [NSJSONSerialization JSONObjectWithData:payloadData options:NSJSONReadingAllowFragments error:nil];
            self.onReceivePayloadDataCallBack(msgDict,true);
        }
      

如此,我们就能亲切的在看到js代码console.log(推送的消息)了

3.编写android插件 代码

weex 会自动生成GetuiPushModule.java

  1. 配置个推sdk

    1. 添加Maven库地址,在以项目名为命名的顶层build.gradle文件中,添加个推maven库地址

      allprojects {
          repositories {
              jcenter()
              mavenCentral()
      
              //个推Maven URL地址
              maven {
                  url "http://mvn.gt.igexin.com/nexus/content/repositories/releases/"
              }
          }
      }
      

    2.在libary/build.gradle文件中引用个推SDK依赖库

     dependencies {
         compile 'com.getui:sdk:2.11.1.0'
     }   
    

    3.配置个推应用参数

    在app/build.gradle文件中的android.defaultConfig下添加manifestPlaceholders,配置个推相关的应用参数

     android {
       ...
       defaultConfig {
         ...
         manifestPlaceholders = [
             GETUI_APP_ID : "APP_ID",
             GETUI_APP_KEY : "APP_KEY",
             GETUI_APP_SECRET : "APP_SECRET"
         ]
       }
     }
    

    4.按照个推文档配置自定义推送服务、接收推送服务事件的service

    5.在GetuiPushModule.java 里面添加initPush方法(正式开始了~)

     @JSMethod
     public void initPush(Map param) {
     
         Log.d("param",param.toString());
         PushManager.getInstance().initialize(this.mWXSDKInstance.getContext(), DemoPushService.class);
         PushManager.getInstance().registerPushIntentService(this.mWXSDKInstance.getContext(), PushIntentService.class);
     }
    

    6.添加 clientId回调和消息回调方法

     @JSMethod(uiThread = true)
     public void onRegisterClient(JSCallback callback){
    
     GetuiPushModule.onRegisterClientCallBack = callback;
    
     }
    
     @JSMethod(uiThread = true)
     public void onReceivePayloadData(JSCallback callback){
    
         GetuiPushModule.onReceivePayloadDataCallBack = callback;
    
     }
    

    上面的callback 使用了一个静态变量存储,方便在PushIntentService 服务里面 执行回调方法给js

    7.在PushIntentService 服务里回调js

     @Override
     public void onReceiveClientId(Context context, String clientid) {
    
         GetuiPushModule.onRegisterClientCallBack.invoke(clientid);
    
         Log.e(TAG, "onReceiveClientId -> " + "clientid = " + clientid);
     }
    
     @Override
     public void onReceiveMessageData(Context context, GTTransmitMessage msg) {
    
         Log.e("onReceiveMessageData", "onReceiveMessageData");
    
         byte[] payload = msg.getPayload();
    
         Map json = (Map) JSON.parse(new String(payload));
    
         GetuiPushModule.onReceivePayloadDataCallBack.invokeAndKeepAlive(json);
     }
    

    可以看到 上面使用两个回调的方式 invoke 和 invokeAndKeepAlive

    invoke适用于一次回调,invokeAndKeepAlive会保持连接,多次回调js

4.调试

npm run build & npm run copy:examples

ios 使用 xcode 打开 playground/ios (没有pod install 的话 先 pod update 下载依赖文件)

android 使用 android studio 打开 playground/android

weex 打包 module

1. 打包上传到weex market 和 js npm

weex plugin login

weex plugin publish

2. 发布iOS pod包

将源代码上传到github,并tag版本号
    添加到本地仓库                  git add ./*
    提交commit到目的仓库            git commit -m "first commit"
    提交到github                   git push -u origin master
    给本地仓库打标签                 git tag -a 0.0.1 -m "Relase version 0.0.1"
    提交标签到远程仓库                git push origin --tags
    注解:就像git push origin master 把本地修改提交到远程仓库一样,-tags可以把本地的打的标签全部提交到远程仓库。
验证.podspec
pod spec lint GetuiPush.podspec --verbose --use-libraries --allow-warnings
发布到CocoaPods
  1. 注册trunk,首先需要使用如下命令注册自己的电脑。这很简单,只要你指明你的邮箱地址(spec文件中的)和名称即可。CocoaPods 会给你填写的邮箱发送验证邮件,点击邮件中的链接就可通过验证。
    pod trunk register scholar-ink@163.com "scholar-ink"
  2. 然后就可以发布你的 Pod 了。
    pod trunk push GetuiPush.podspec --use-libraries --allow-warnings
    发布成功后,需要等待pod团队审核(貌似1~2小时,还是npm好,不需要审核,这也是为什么npm一大堆的第三方包😁😁),审核成功后就可以使用pod search GetuiPush搜索到你的 Pod 了!如果没有找到 可以使用 pod setup 更新本地pod依赖库后再执行 pod search
版本升级

当需要更新 Pod 版本的时候,修改 .podspec 中的 s.version 为更高的版本号,并修改 s.source 中对应的 Git 版本。提交到Git,并打上对应tag。然后再次执行pod trunk push GetuiPush.podspec将新的 .podspec 发布到 CocoaPods。

为了更新更加方便,版本控制更加清晰,s.source 建议采用如下写法:
s.source = { :git => "https://github.com/scholar-ink/weex-plugin-getui-push.git", :tag => s.version}

3.打包android代码

可参考http://blog.csdn.net/jiankeufo/article/details/71191865

贴出我修改的重要几个地方:

1.在你modul的build.gradle文件中配置插件

    apply plugin: 'com.github.dcendents.android-maven'
    apply plugin: 'com.jfrog.bintray'
  1. 在你Project的build.gradle文件中加入Maven和Jfrog Bintray的依赖插件:

     classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'
     classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
    
  2. 重要配置 有注释的配置特别关注

     def siteUrl = 'https://github.com/scholar-ink/weex-plugin-getui-push'      // 项目的主页
     def gitUrl = 'https://github.com/scholar-ink/weex-plugin-getui-push.git'   // Git仓库的url
     version = "0.0.1"       //这个是版本号,必须填写
     group = "org.weex.plugin"                                        // Maven Group ID for the artifact,一般填你唯一的包名
     
     install{
         repositories.mavenInstaller {
             // This generates POM.xml with proper parameters
             pom {
                 project {
                     packaging 'aar'
                     // Add your description here
                     name 'getui-push extend for weex'   //项目描述
                     url siteUrl
                     // Set your license
                     licenses {
                         license {
                             name 'The Apache Software License, Version 2.0'
                             url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                         }
                     }
                     developers {
                         developer {
                             id 'zhouink'         //填写bintray或者github的用户名
                             name 'zhouchao'     //姓名
                             email 'zhouc1120@gmail.com'//邮箱
                         }
                     }
                     scm {
                         connection gitUrl
                         developerConnection gitUrl
                         url siteUrl
                     }
                 }
             }
         }
     }
     
     task sourcesJar(type: Jar) {
         from android.sourceSets.main.java.srcDirs
         classifier = 'sources'
     }
     task javadoc(type: Javadoc) {
         source = android.sourceSets.main.java.srcDirs
         classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
     }
     task javadocJar(type: Jar, dependsOn: javadoc) {
         classifier = 'javadoc'
         from javadoc.destinationDir
     }
     artifacts {
         archives javadocJar
         archives sourcesJar
     }
     Properties properties = new Properties()
     properties.load(project.rootProject.file('local.properties').newDataInputStream())
     bintray {
         user = properties.getProperty("bintray.user") //账号和apiKey
         key = properties.getProperty("bintray.apikey")
         configurations = ['archives']
         pkg {
             repo = "maven" //仓库名,注意不是项目名
             name = "getuipush"  //发布到JCenter上的项目名字
             websiteUrl = siteUrl
             vcsUrl = gitUrl
             licenses = ["Apache-2.0"]
             publish = true
         }
    }    
    

值得提到的一点是 addPackageToJCenter 是需要审核的,而且审核时间还不短,郁闷中~完全没有js 的npm php的composer来的实在~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,158评论 4 370
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,600评论 1 307
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,785评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,655评论 0 220
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,075评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,002评论 1 225
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,146评论 2 318
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,918评论 0 211
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,671评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,838评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,318评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,636评论 3 263
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,343评论 3 244
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,187评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,982评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,126评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,934评论 2 279

推荐阅读更多精彩内容