HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

关于 iOS 上架时,Missing Push Notification Entitlement 的问题

  不知道从何时开始,提交 App 到 App Store 上审核以后,当天会在邮箱中接受到一封标题为:iTunes Connect: Your app "XXX" (Apple ID: xxxxxxxx) has one or more issues 的邮件,内容如下:

Dear developer,

We have discovered one or more issues with your recent delivery for "XXX". Your delivery was successful, but you may wish to correct the following issues in your next delivery:
Missing Push Notification Entitlement - Your app appears to include API used to register with the Apple Push Notification service, but the app signature's entitlements do not include the "aps-environment" entitlement. If your app uses the Apple Push Notification service, make sure your App ID is enabled for Push Notification in the Provisioning Portal, and resubmit after signing your app with a Distribution provisioning profile that includes the "aps-environment" entitlement. See "Provisioning and Development" in the Local and Push Notification Programming Guide for more information. If your app does not use the Apple Push Notification service, no action is required. You may remove the API from future submissions to stop this warning. If you use a third-party framework, you may need to contact the developer for information on removing the API.

After you’ve corrected the issues, you can use Xcode or Application Loader to upload a new binary to iTunes Connect.

Regards,

The App Store team

  很多开发者都会被这封邮件英文邮件弄昏头,以为自己的 App 审核被拒绝。但其实,根据苹果开发者论坛的咨询和回复:https://forums.developer.apple.com/thread/15011,这封邮件仅仅是一封警告邮件,如果 App 中并没有使用到推送功能的话,开发者可以直接忽略到这封邮件,因为它并不会影响到 App 的审核。

继续阅读 »

  不知道从何时开始,提交 App 到 App Store 上审核以后,当天会在邮箱中接受到一封标题为:iTunes Connect: Your app "XXX" (Apple ID: xxxxxxxx) has one or more issues 的邮件,内容如下:

Dear developer,

We have discovered one or more issues with your recent delivery for "XXX". Your delivery was successful, but you may wish to correct the following issues in your next delivery:
Missing Push Notification Entitlement - Your app appears to include API used to register with the Apple Push Notification service, but the app signature's entitlements do not include the "aps-environment" entitlement. If your app uses the Apple Push Notification service, make sure your App ID is enabled for Push Notification in the Provisioning Portal, and resubmit after signing your app with a Distribution provisioning profile that includes the "aps-environment" entitlement. See "Provisioning and Development" in the Local and Push Notification Programming Guide for more information. If your app does not use the Apple Push Notification service, no action is required. You may remove the API from future submissions to stop this warning. If you use a third-party framework, you may need to contact the developer for information on removing the API.

After you’ve corrected the issues, you can use Xcode or Application Loader to upload a new binary to iTunes Connect.

Regards,

The App Store team

  很多开发者都会被这封邮件英文邮件弄昏头,以为自己的 App 审核被拒绝。但其实,根据苹果开发者论坛的咨询和回复:https://forums.developer.apple.com/thread/15011,这封邮件仅仅是一封警告邮件,如果 App 中并没有使用到推送功能的话,开发者可以直接忽略到这封邮件,因为它并不会影响到 App 的审核。

收起阅读 »

如何选择Android模拟器?

Android

Android开发中,很多Android开发者都遇到如何选择一款好用的模拟器这个问题,今天就在这总结一下,关于Android模拟器该如何选择的问题。

1、Genymotion 模拟器:

优点:速度很快,比Android-SDK,基本上调试个UI足够用了,更新也比较容易,官网也容易访问,还有中文的介绍。
缺点:需要注册,免费版有功能限制,但是足够用了,需要安装配置,稍显麻烦,在Eclipse和Android Studio中使用需要单独配置,还好官网都有介绍,只不过是英文的。

2、Android-SDK 模拟器:

优点:配置简单;
缺点:卡的要死,因为国内对于Google官网访问的限制所以更新也是麻烦事,所以不推荐使用。

3、开发板或者真机:

缺点:没有Android机器的需要花钱买一个。
优点:快、真实、可以调试任何的程序,真实的反应你的程序问题。

继续阅读 »

Android开发中,很多Android开发者都遇到如何选择一款好用的模拟器这个问题,今天就在这总结一下,关于Android模拟器该如何选择的问题。

1、Genymotion 模拟器:

优点:速度很快,比Android-SDK,基本上调试个UI足够用了,更新也比较容易,官网也容易访问,还有中文的介绍。
缺点:需要注册,免费版有功能限制,但是足够用了,需要安装配置,稍显麻烦,在Eclipse和Android Studio中使用需要单独配置,还好官网都有介绍,只不过是英文的。

2、Android-SDK 模拟器:

优点:配置简单;
缺点:卡的要死,因为国内对于Google官网访问的限制所以更新也是麻烦事,所以不推荐使用。

3、开发板或者真机:

缺点:没有Android机器的需要花钱买一个。
优点:快、真实、可以调试任何的程序,真实的反应你的程序问题。

收起阅读 »

Android开发中如何简化findViewById类型转换

Android

写布局在Android开发中是最重要也是非常麻烦的一件事,不仅会耗费Android开发者的大量时间,而且初始化控件,写findViewById去类型转换也是非常耗时的,今天就告诉你一个小窍门,通过泛型来简化findViewById类型转换。

具体做法如下

1创建一个基类,BaseActivity并继承Activity

方法如下:
public class BaseActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
protected <T extends View> T generateFindViewById(int id) {
//return返回view时,加上泛型T
return (T) findViewById(id);
}
}

2自己写的Activity都去继承BaseActivity
之后我们自己写的每一个Activity都去继承BaseActivity,然后在初始化控件时直接使用generateFindViewById来代替findViewById即可。

这个问题,可能只存在于还在用eclipse开发,或者是使用了Android Studio之后,但是不会使用ButterKnife Zelezny 这个工具的的童鞋,学习了这个小窍门之后,你就能摆脱这样的痛苦,提高自己的开发效率。

继续阅读 »

写布局在Android开发中是最重要也是非常麻烦的一件事,不仅会耗费Android开发者的大量时间,而且初始化控件,写findViewById去类型转换也是非常耗时的,今天就告诉你一个小窍门,通过泛型来简化findViewById类型转换。

具体做法如下

1创建一个基类,BaseActivity并继承Activity

方法如下:
public class BaseActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
protected <T extends View> T generateFindViewById(int id) {
//return返回view时,加上泛型T
return (T) findViewById(id);
}
}

2自己写的Activity都去继承BaseActivity
之后我们自己写的每一个Activity都去继承BaseActivity,然后在初始化控件时直接使用generateFindViewById来代替findViewById即可。

这个问题,可能只存在于还在用eclipse开发,或者是使用了Android Studio之后,但是不会使用ButterKnife Zelezny 这个工具的的童鞋,学习了这个小窍门之后,你就能摆脱这样的痛苦,提高自己的开发效率。

收起阅读 »

Linux下开发 5+ app

linux

​公司开发环境是linux, 为了用5+ SDK, 不得不寻找HBuilder以外的方法, 同时项目中需集成第三方SDK, 有本地代码需要本地打包. 此为背景.

假设app名为foo, 不管是在线还是本地打包, 代码目录会被放存储卡的/Android/data/com.foo/apps/foo/www目录下, 所以要实现实时刷新, 只需要解决文件同步和刷新界面的问题.

1. 文件同步

有现成的工具可以使用, adb-sync, google的python脚本用于实现本地某个目录和android某个目录的同步. github地址https://github.com/google/adb-sync

我的用法: 写个小脚本每5秒同步一次

#!/bin/bash  
while [ true ]; do  
/bin/sleep 5  
./adb-sync --delete /media/xxx/app/ /storage/emulated/0/Android/data/com.foo/apps/foo/www/  
done

2. 打开5+ runtime的webview调试

本地打包会把chrome调试关闭. 可以在首页加入以下代码:

mui.plusReady(function(){  
    var webView = plus.android.importClass("android.webkit.WebView");  
    webView.setWebContentsDebuggingEnabled(true);  
});

这样本地打包的也可以用chrome调试了, PS: chrome调试参考http://ask.dcloud.net.cn/article/69

3. webview自动刷新

目前没有找到好的方法, 在chrome调试时手动F5刷新就好了

结论

最终的流程是: 找个顺手的IDE, 编辑代码 -> 保存 -> 切换到chrome -> F5刷新看效果

比不上windows下HBuilder的爽快, 但至少可以在linux下比较快的码代码了, 嗯

继续阅读 »

​公司开发环境是linux, 为了用5+ SDK, 不得不寻找HBuilder以外的方法, 同时项目中需集成第三方SDK, 有本地代码需要本地打包. 此为背景.

假设app名为foo, 不管是在线还是本地打包, 代码目录会被放存储卡的/Android/data/com.foo/apps/foo/www目录下, 所以要实现实时刷新, 只需要解决文件同步和刷新界面的问题.

1. 文件同步

有现成的工具可以使用, adb-sync, google的python脚本用于实现本地某个目录和android某个目录的同步. github地址https://github.com/google/adb-sync

我的用法: 写个小脚本每5秒同步一次

#!/bin/bash  
while [ true ]; do  
/bin/sleep 5  
./adb-sync --delete /media/xxx/app/ /storage/emulated/0/Android/data/com.foo/apps/foo/www/  
done

2. 打开5+ runtime的webview调试

本地打包会把chrome调试关闭. 可以在首页加入以下代码:

mui.plusReady(function(){  
    var webView = plus.android.importClass("android.webkit.WebView");  
    webView.setWebContentsDebuggingEnabled(true);  
});

这样本地打包的也可以用chrome调试了, PS: chrome调试参考http://ask.dcloud.net.cn/article/69

3. webview自动刷新

目前没有找到好的方法, 在chrome调试时手动F5刷新就好了

结论

最终的流程是: 找个顺手的IDE, 编辑代码 -> 保存 -> 切换到chrome -> F5刷新看效果

比不上windows下HBuilder的爽快, 但至少可以在linux下比较快的码代码了, 嗯

收起阅读 »

Swift那些鲜为人知的特性

iOS

iOS开发中,Swift语言有各种各样缺乏文档记录的特性,这些鲜为人知的特性放在那里,等着我们去发现去使用,现在就让我们看看有哪些特性吧

@transparent
该特性会导致编译器在管道(pipeline)中更早地将函数内联。它用于“像+(Int, Int)这样非常原始的函数”,而“不应该用于独立函数”。
甚至在没有优化设置的调试模式下,@transparent特性函数就会被内联,所以在调用“1+1”这样的函数时候并不会特别慢,另外这个特性与@inline(__always)非常类似。

@availability
这个特性可以用来标识某些函数只在某些平台或版本上可用。第一个参数是平台,可以用星号(*)代表一切可用,还可以是iOS或OS X。因为如果需要针对不同的平台,就要指定多个@availability属性。

如果需要表示该函数在某个给定的平台完全不可用时,可以将第二个参数置为unavailable。此外,还可以用introduced,deprecated和obsoleted来指定一个或是多个版本的组合:obsoleted意味着该项已经删除,deprecated仅仅表示如果使用就会给予警告。最后可以设置message的值,如果该项被使用了就由编译器输出。如果调用另一个被标志为@noreturn的函数,那么编译器会忽略掉当前函数中缺失的返回值(missing return values),因为编译器理解程序的控制流。

@inline
这个特性为编译器提供了内联提示。有效的取值是always和never。除非认为必须要用这两个值,否则就不会使用它(特别是always)。到目前为止与其相关的规则还不是很明确,在有限的测试下,它可以正常地工作,但还要视具体情况而定。
进一步的解释:尽管底层虚拟机(Low Level Virtual Machine, LLVM)有强制内联的概念,但目前还不知道这个@inline特性是否与其直接映射,也不知道是否存在大小方面的限制,但这将会导致编译器忽略这一点而跳过内联。理论上说应该是这样的,但我不保证一定是。
注意(当优化设置关闭时)在调试模式下的构建将忽略@inline。

@asmname
该属性给出了函数、方法或属性实现的符号名称。如果已经知道对应的函数参数及其类型,那么就可以直接调用Swift的内部标准库函数,甚至不用头文件,也可以方便地调用C语言编写的函数:@asmname("function") func f()

@semantics
这又是另一个谜。参数看起来像是array.mutate_unknown或array.init这样的字符串数组。想必这是要告诉编译器(或静态分析器)函数是如何工作的。

@unsafe_no_objc_tagged_pointer
上面这个仍然是个谜,但据猜测,它是在告诉Swift与Objective-C联系的时候不要使用tagged pointer。

继续阅读 »

iOS开发中,Swift语言有各种各样缺乏文档记录的特性,这些鲜为人知的特性放在那里,等着我们去发现去使用,现在就让我们看看有哪些特性吧

@transparent
该特性会导致编译器在管道(pipeline)中更早地将函数内联。它用于“像+(Int, Int)这样非常原始的函数”,而“不应该用于独立函数”。
甚至在没有优化设置的调试模式下,@transparent特性函数就会被内联,所以在调用“1+1”这样的函数时候并不会特别慢,另外这个特性与@inline(__always)非常类似。

@availability
这个特性可以用来标识某些函数只在某些平台或版本上可用。第一个参数是平台,可以用星号(*)代表一切可用,还可以是iOS或OS X。因为如果需要针对不同的平台,就要指定多个@availability属性。

如果需要表示该函数在某个给定的平台完全不可用时,可以将第二个参数置为unavailable。此外,还可以用introduced,deprecated和obsoleted来指定一个或是多个版本的组合:obsoleted意味着该项已经删除,deprecated仅仅表示如果使用就会给予警告。最后可以设置message的值,如果该项被使用了就由编译器输出。如果调用另一个被标志为@noreturn的函数,那么编译器会忽略掉当前函数中缺失的返回值(missing return values),因为编译器理解程序的控制流。

@inline
这个特性为编译器提供了内联提示。有效的取值是always和never。除非认为必须要用这两个值,否则就不会使用它(特别是always)。到目前为止与其相关的规则还不是很明确,在有限的测试下,它可以正常地工作,但还要视具体情况而定。
进一步的解释:尽管底层虚拟机(Low Level Virtual Machine, LLVM)有强制内联的概念,但目前还不知道这个@inline特性是否与其直接映射,也不知道是否存在大小方面的限制,但这将会导致编译器忽略这一点而跳过内联。理论上说应该是这样的,但我不保证一定是。
注意(当优化设置关闭时)在调试模式下的构建将忽略@inline。

@asmname
该属性给出了函数、方法或属性实现的符号名称。如果已经知道对应的函数参数及其类型,那么就可以直接调用Swift的内部标准库函数,甚至不用头文件,也可以方便地调用C语言编写的函数:@asmname("function") func f()

@semantics
这又是另一个谜。参数看起来像是array.mutate_unknown或array.init这样的字符串数组。想必这是要告诉编译器(或静态分析器)函数是如何工作的。

@unsafe_no_objc_tagged_pointer
上面这个仍然是个谜,但据猜测,它是在告诉Swift与Objective-C联系的时候不要使用tagged pointer。

收起阅读 »

Mac版6.7.0真机联调控制台无法使用的解决办法

HBuilder

1.关闭HBuilder

  1. 对HBuilder.app点右键,显示包内容如下图

    3.拷贝jre到Contents目录下(注意是拷贝,不是剪切,这里的jre仍需要保留),我们会在今天晚上(2015-11-9)发布紧急更新
继续阅读 »

1.关闭HBuilder

  1. 对HBuilder.app点右键,显示包内容如下图

    3.拷贝jre到Contents目录下(注意是拷贝,不是剪切,这里的jre仍需要保留),我们会在今天晚上(2015-11-9)发布紧急更新
收起阅读 »

团队承接hbuilder,h5+,mui的外包

外包

如题:有需要外包的请联系我,前端,后台都可以全包,QQ1046373779

如题:有需要外包的请联系我,前端,后台都可以全包,QQ1046373779

iOS平台设置应用访问白名单(LSApplicationQueriesSchemes)

iOS 5+App开发

此文档不再维护,请参考新文档地址:https://uniapp.dcloud.io/tutorial/app-ios-schemewhitelist

从iOS9开始系统策略更新,加入对用户隐私以及禁止扫描系统信息的控制,限制了scheme协议的访问。需要将其它App注册的scheme添加到应用访问白名单(LSApplicationQueriesSchemes)中才能实现以下功能:

  • 通过scheme检查其它App是否安装,不添加到白名单则检测结果为未安装(即使应用已经安装)
  • 通过scheme协议调用其它App,不添加到白名单则会弹出提示框,用户确认后才能启动应用,添加到白名单列表后则无需用户确认直接启动应用。

设置应用跳转白名单列表

打开项目的manifest.json文件,切换到“代码视图”

  • 5+App项目
    在manifest.json文件的"plus"->"distribute"->"apple"下添加urlschemewhitelist节点数据如下:

    "plus": {    
    "distribute": {    
    "apple": {    
        "urlschemewhitelist": [    
                "BaiduSSO",  
                "qqmusic"  
        ],    
        //...    
    },    
    //...    
    },    
    //...    
    },    
    //... 
  • uni-app项目
    把上面的urlschemewhitelist节点数据放到manifest.json的"app-plus"->"distribute"->"ios"节点下

注意:保存后提交App云端打包后才能生效,列表最多可添加50个

App云端打包默认添加的白名单列表

为了方便开发者调用一些常用的第三方应用,云端打包默认已经添加以下白名单

lightsky  
shark.video  
bobo  
snssdk32  
pptv  
bilibili  
kugouURL  
gaeagj  
qqnews  
zhihu  
doubanradio  
openApp.jdMobile  
imeituan  
tmall  
dianping  
vipshop  
yanxuan  
wccbyihaodian  
taobao  
suning  
kaola  
ctrip  
kuaikanmanhua  
gugutouchmanga  
qrxs  
mailmaster  
jcnhers  
wbmain  
yixin  
ydcourse  
ntesopen  
yddict  
shanbay  
tencentweiboSdkv2  
weibosdk2.5  
sinaweibo  
sinaweibohd  
cydia  
weixin  
wechat  
weibosdk  
mqq  
mqqapi  
mqzone  
wtloginmqq2  
mqqopensdkapiV3  
mqqwpa  
mqqopensdkapiV2  
mqqOpensdkSSoL  
hbuilder  
streamapp  
baidumap  
iosamap  
qqmap

iOS平台设置UrlSchemes参考:https://ask.dcloud.net.cn/article/64

继续阅读 »

此文档不再维护,请参考新文档地址:https://uniapp.dcloud.io/tutorial/app-ios-schemewhitelist

从iOS9开始系统策略更新,加入对用户隐私以及禁止扫描系统信息的控制,限制了scheme协议的访问。需要将其它App注册的scheme添加到应用访问白名单(LSApplicationQueriesSchemes)中才能实现以下功能:

  • 通过scheme检查其它App是否安装,不添加到白名单则检测结果为未安装(即使应用已经安装)
  • 通过scheme协议调用其它App,不添加到白名单则会弹出提示框,用户确认后才能启动应用,添加到白名单列表后则无需用户确认直接启动应用。

设置应用跳转白名单列表

打开项目的manifest.json文件,切换到“代码视图”

  • 5+App项目
    在manifest.json文件的"plus"->"distribute"->"apple"下添加urlschemewhitelist节点数据如下:

    "plus": {    
    "distribute": {    
    "apple": {    
        "urlschemewhitelist": [    
                "BaiduSSO",  
                "qqmusic"  
        ],    
        //...    
    },    
    //...    
    },    
    //...    
    },    
    //... 
  • uni-app项目
    把上面的urlschemewhitelist节点数据放到manifest.json的"app-plus"->"distribute"->"ios"节点下

注意:保存后提交App云端打包后才能生效,列表最多可添加50个

App云端打包默认添加的白名单列表

为了方便开发者调用一些常用的第三方应用,云端打包默认已经添加以下白名单

lightsky  
shark.video  
bobo  
snssdk32  
pptv  
bilibili  
kugouURL  
gaeagj  
qqnews  
zhihu  
doubanradio  
openApp.jdMobile  
imeituan  
tmall  
dianping  
vipshop  
yanxuan  
wccbyihaodian  
taobao  
suning  
kaola  
ctrip  
kuaikanmanhua  
gugutouchmanga  
qrxs  
mailmaster  
jcnhers  
wbmain  
yixin  
ydcourse  
ntesopen  
yddict  
shanbay  
tencentweiboSdkv2  
weibosdk2.5  
sinaweibo  
sinaweibohd  
cydia  
weixin  
wechat  
weibosdk  
mqq  
mqqapi  
mqzone  
wtloginmqq2  
mqqopensdkapiV3  
mqqwpa  
mqqopensdkapiV2  
mqqOpensdkSSoL  
hbuilder  
streamapp  
baidumap  
iosamap  
qqmap

iOS平台设置UrlSchemes参考:https://ask.dcloud.net.cn/article/64

收起阅读 »

Android插件,TTS语音合成(文字转化语音)。

插件开发 插件

相关介绍

概念介绍

语音合成是实现人机语音交互,建立一个有听和讲能力的交互系统所必需的关键技术。随着语音技术的发展,百度自主研发了语音合成系统(TTS),功能是接受用户发送的文本,生成语音发送给用户。
对本文中将提到的概念约定如下:
语音合成:将文本合成为语音,即声音文件。
合成引擎:将文本合成为语音的核心模块。
TTS:Text To Speech,即“从文本到语音”。
BDTTSClient:语音合成 SDK 简称,详见下条。
语音合成 SDK:即本开发包,文中简称为 BDTTSClient。BDTTSClient 是一个封装了网络收发、音频播放功能的语音合成解决方案。借助 BDTTSClient 可以快速地在应用程序中集成语音合成功能。
百度语音

合成方式

1.离在线语音合成
2.在线语音合成(本文使用方式)

应用场景

我们团队的应用场景是在推送消息后,需要播放推送消息。

准备事项

1.下载Android 平台 HTML5+ SDK 。
2.注册百度开发者,创建应用,开通服务,请参考集成指南
3.下载在线语音合成SDK_Android版。

实现步骤

1.先导入5+SDK就不多说了,参考Android平台第三方插件开发指导
2.添加BDTTSClient到工程(将开发包中的 libs 目录整体拷贝到工程目录,libs 目录包括了各平台的 SO 库,开发者视应用需要可以进行删减。galaxy_lite.jar 是百度 Android 公共基础库。)
3.权限声明(需要在 AndroidManifest.xml 文件,增加以上三个权限)

<uses-permission android:name="android.permission.INTERNET" />  
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />  
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

4.集成java代码

import org.json.JSONArray;  
import com.baidu.speechsynthesizer.SpeechSynthesizer;  
import com.baidu.speechsynthesizer.SpeechSynthesizerListener;  
import com.baidu.speechsynthesizer.publicutility.SpeechError;  
import android.media.AudioManager;  
import android.util.Log;  
import io.dcloud.common.DHInterface.IWebview;  
import io.dcloud.common.DHInterface.StandardFeature;  
import io.dcloud.common.util.JSUtil;  
public class baidutts extends StandardFeature implements SpeechSynthesizerListener{  
    private IWebview iwv ;  
    private String text;  
    private SpeechSynthesizer speechSynthesizer;  
    private static final String TAG = "zlz";  
    public void speak(IWebview pWebview, JSONArray array)  
    {  
        iwv = pWebview;  
        String CallBackID = array.optString(0);  
        JSONArray newArray = new JSONArray();  
        newArray.put(array.optString(1));  
        //前台传过来的文本信息  
        text = array.optString(1);  
        //Log.i(TAG, text);  
        initialTts();  
        JSUtil.execCallback(pWebview, CallBackID, newArray, JSUtil.OK, false);  
    }  
    //百度TTS初始化  
    private void initialTts() {  
        speechSynthesizer = new SpeechSynthesizer(iwv.getContext(),  
                "holder", this);  
        // 此处需要将setApiKey方法的两个参数替换为你在百度开发者中心注册应用所得到的apiKey和secretKey  
        speechSynthesizer.setApiKey("your-apiKey", "your-secretKey");  
        speechSynthesizer.setAudioStreamType(AudioManager.STREAM_MUSIC);  
        //setVolumeControlStream(AudioManager.STREAM_MUSIC);  
        new Thread(new Runnable() {  
            @Override  
            public void run() {  
                setParams();  
                int ret = speechSynthesizer.speak(text);  
                if (ret != 0) {  
                    Log.i(TAG,"开始合成器失败" );  
                }  
            }  
        }).start();  

    }  
    private void setParams() {  
        speechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEAKER, "0");  
        speechSynthesizer.setParam(SpeechSynthesizer.PARAM_VOLUME, "5");  
        speechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEED, "5");  
        speechSynthesizer.setParam(SpeechSynthesizer.PARAM_PITCH, "5");  
        speechSynthesizer.setParam(SpeechSynthesizer.PARAM_AUDIO_ENCODE, SpeechSynthesizer.AUDIO_ENCODE_AMR);  
        speechSynthesizer.setParam(SpeechSynthesizer.PARAM_AUDIO_RATE, SpeechSynthesizer.AUDIO_BITRATE_AMR_15K85);  
    }  
    @Override  
    public void onBufferProgressChanged(SpeechSynthesizer arg0, int arg1) {}  
    @Override  
    public void onCancel(SpeechSynthesizer arg0) {}  
    @Override  
    public void onError(SpeechSynthesizer arg0, SpeechError arg1) {}  
    @Override  
    public void onNewDataArrive(SpeechSynthesizer arg0, byte[] arg1, boolean arg2) {}  
    @Override  
    public void onSpeechFinish(SpeechSynthesizer arg0) {}  
    @Override  
    public void onSpeechPause(SpeechSynthesizer arg0) {}  
    @Override  
    public void onSpeechProgressChanged(SpeechSynthesizer arg0, int arg1) {}  
    @Override  
    public void onSpeechResume(SpeechSynthesizer arg0) {}  
    @Override  
    public void onSpeechStart(SpeechSynthesizer arg0) {}  
    @Override  
    public void onStartWorking(SpeechSynthesizer arg0) {}  
    @Override  
    public void onSynthesizeFinish(SpeechSynthesizer arg0) {}  
}

5.前台javascript代码

document.addEventListener( "plusready",  function()  
{  
    var _BARCODE = 'kxdPlugins',  
        B = window.plus.bridge;  
    var kxdPlugins =   
    {  
        // 声明异步返回方法  
        speak : function (Argus, successCallback, errorCallback )   
        {  
            var success = typeof successCallback !== 'function' ? null : function(args)   
            {  
                successCallback(args);  
            },  
            fail = typeof errorCallback !== 'function' ? null : function(code)   
            {  
                errorCallback(code);  
            };  
            callbackID = B.callbackId(success, fail);  
            // 通知Native层plugintest扩展插件运行”speak”方法  
            return B.exec(_BARCODE, "speak", [callbackID, Argus]);  
        }  
    };  
    window.plus.kxdPlugins = kxdPlugins;  
}, true );

使用方式

和普通的API调用方式一样:plus.kxdPlugins.speak("这是语音播放的文字内容");

注意事项

1.在/assets/data/properties.xml中添加插件权限。
2.在/assets/apps/appid/www/manifest.json 中添加对应插件权限。
3.在/AndroidManifest.xml 文件中添加对应的百度语音合成权限。

继续阅读 »

相关介绍

概念介绍

语音合成是实现人机语音交互,建立一个有听和讲能力的交互系统所必需的关键技术。随着语音技术的发展,百度自主研发了语音合成系统(TTS),功能是接受用户发送的文本,生成语音发送给用户。
对本文中将提到的概念约定如下:
语音合成:将文本合成为语音,即声音文件。
合成引擎:将文本合成为语音的核心模块。
TTS:Text To Speech,即“从文本到语音”。
BDTTSClient:语音合成 SDK 简称,详见下条。
语音合成 SDK:即本开发包,文中简称为 BDTTSClient。BDTTSClient 是一个封装了网络收发、音频播放功能的语音合成解决方案。借助 BDTTSClient 可以快速地在应用程序中集成语音合成功能。
百度语音

合成方式

1.离在线语音合成
2.在线语音合成(本文使用方式)

应用场景

我们团队的应用场景是在推送消息后,需要播放推送消息。

准备事项

1.下载Android 平台 HTML5+ SDK 。
2.注册百度开发者,创建应用,开通服务,请参考集成指南
3.下载在线语音合成SDK_Android版。

实现步骤

1.先导入5+SDK就不多说了,参考Android平台第三方插件开发指导
2.添加BDTTSClient到工程(将开发包中的 libs 目录整体拷贝到工程目录,libs 目录包括了各平台的 SO 库,开发者视应用需要可以进行删减。galaxy_lite.jar 是百度 Android 公共基础库。)
3.权限声明(需要在 AndroidManifest.xml 文件,增加以上三个权限)

<uses-permission android:name="android.permission.INTERNET" />  
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />  
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

4.集成java代码

import org.json.JSONArray;  
import com.baidu.speechsynthesizer.SpeechSynthesizer;  
import com.baidu.speechsynthesizer.SpeechSynthesizerListener;  
import com.baidu.speechsynthesizer.publicutility.SpeechError;  
import android.media.AudioManager;  
import android.util.Log;  
import io.dcloud.common.DHInterface.IWebview;  
import io.dcloud.common.DHInterface.StandardFeature;  
import io.dcloud.common.util.JSUtil;  
public class baidutts extends StandardFeature implements SpeechSynthesizerListener{  
    private IWebview iwv ;  
    private String text;  
    private SpeechSynthesizer speechSynthesizer;  
    private static final String TAG = "zlz";  
    public void speak(IWebview pWebview, JSONArray array)  
    {  
        iwv = pWebview;  
        String CallBackID = array.optString(0);  
        JSONArray newArray = new JSONArray();  
        newArray.put(array.optString(1));  
        //前台传过来的文本信息  
        text = array.optString(1);  
        //Log.i(TAG, text);  
        initialTts();  
        JSUtil.execCallback(pWebview, CallBackID, newArray, JSUtil.OK, false);  
    }  
    //百度TTS初始化  
    private void initialTts() {  
        speechSynthesizer = new SpeechSynthesizer(iwv.getContext(),  
                "holder", this);  
        // 此处需要将setApiKey方法的两个参数替换为你在百度开发者中心注册应用所得到的apiKey和secretKey  
        speechSynthesizer.setApiKey("your-apiKey", "your-secretKey");  
        speechSynthesizer.setAudioStreamType(AudioManager.STREAM_MUSIC);  
        //setVolumeControlStream(AudioManager.STREAM_MUSIC);  
        new Thread(new Runnable() {  
            @Override  
            public void run() {  
                setParams();  
                int ret = speechSynthesizer.speak(text);  
                if (ret != 0) {  
                    Log.i(TAG,"开始合成器失败" );  
                }  
            }  
        }).start();  

    }  
    private void setParams() {  
        speechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEAKER, "0");  
        speechSynthesizer.setParam(SpeechSynthesizer.PARAM_VOLUME, "5");  
        speechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEED, "5");  
        speechSynthesizer.setParam(SpeechSynthesizer.PARAM_PITCH, "5");  
        speechSynthesizer.setParam(SpeechSynthesizer.PARAM_AUDIO_ENCODE, SpeechSynthesizer.AUDIO_ENCODE_AMR);  
        speechSynthesizer.setParam(SpeechSynthesizer.PARAM_AUDIO_RATE, SpeechSynthesizer.AUDIO_BITRATE_AMR_15K85);  
    }  
    @Override  
    public void onBufferProgressChanged(SpeechSynthesizer arg0, int arg1) {}  
    @Override  
    public void onCancel(SpeechSynthesizer arg0) {}  
    @Override  
    public void onError(SpeechSynthesizer arg0, SpeechError arg1) {}  
    @Override  
    public void onNewDataArrive(SpeechSynthesizer arg0, byte[] arg1, boolean arg2) {}  
    @Override  
    public void onSpeechFinish(SpeechSynthesizer arg0) {}  
    @Override  
    public void onSpeechPause(SpeechSynthesizer arg0) {}  
    @Override  
    public void onSpeechProgressChanged(SpeechSynthesizer arg0, int arg1) {}  
    @Override  
    public void onSpeechResume(SpeechSynthesizer arg0) {}  
    @Override  
    public void onSpeechStart(SpeechSynthesizer arg0) {}  
    @Override  
    public void onStartWorking(SpeechSynthesizer arg0) {}  
    @Override  
    public void onSynthesizeFinish(SpeechSynthesizer arg0) {}  
}

5.前台javascript代码

document.addEventListener( "plusready",  function()  
{  
    var _BARCODE = 'kxdPlugins',  
        B = window.plus.bridge;  
    var kxdPlugins =   
    {  
        // 声明异步返回方法  
        speak : function (Argus, successCallback, errorCallback )   
        {  
            var success = typeof successCallback !== 'function' ? null : function(args)   
            {  
                successCallback(args);  
            },  
            fail = typeof errorCallback !== 'function' ? null : function(code)   
            {  
                errorCallback(code);  
            };  
            callbackID = B.callbackId(success, fail);  
            // 通知Native层plugintest扩展插件运行”speak”方法  
            return B.exec(_BARCODE, "speak", [callbackID, Argus]);  
        }  
    };  
    window.plus.kxdPlugins = kxdPlugins;  
}, true );

使用方式

和普通的API调用方式一样:plus.kxdPlugins.speak("这是语音播放的文字内容");

注意事项

1.在/assets/data/properties.xml中添加插件权限。
2.在/assets/apps/appid/www/manifest.json 中添加对应插件权限。
3.在/AndroidManifest.xml 文件中添加对应的百度语音合成权限。

收起阅读 »

获取图片当前旋转状态

Orientation

今日开发过程中遇见从相册选择或者自拍照片,显示时为横向。故封装如下代码,希望对大家有所帮助。

function getImgOrientation (filePath) {  
            var ExifInterface = plus.android.importClass("android.media.ExifInterface");  
            var exifInterface = new ExifInterface(filePath.replace("file:///", ""));  
            var orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);  
            var degree = 0;  
            switch (orientation) {  
                case ExifInterface.ORIENTATION_ROTATE_90:  
                    degree = 90;  
                    break;  
                case ExifInterface.ORIENTATION_ROTATE_180:  
                    degree = 180;  
                    break;  
                case ExifInterface.ORIENTATION_ROTATE_270:  
                    degree = 270;  
                    break;  
            }  
            return degree;  
        }
继续阅读 »

今日开发过程中遇见从相册选择或者自拍照片,显示时为横向。故封装如下代码,希望对大家有所帮助。

function getImgOrientation (filePath) {  
            var ExifInterface = plus.android.importClass("android.media.ExifInterface");  
            var exifInterface = new ExifInterface(filePath.replace("file:///", ""));  
            var orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);  
            var degree = 0;  
            switch (orientation) {  
                case ExifInterface.ORIENTATION_ROTATE_90:  
                    degree = 90;  
                    break;  
                case ExifInterface.ORIENTATION_ROTATE_180:  
                    degree = 180;  
                    break;  
                case ExifInterface.ORIENTATION_ROTATE_270:  
                    degree = 270;  
                    break;  
            }  
            return degree;  
        }
收起阅读 »

整包(apk/ipa)升级

升级

官方已发布APP升级中心,支持原生APP整包升级和wgt资源包升级。详见

5+应用可使用以下方式进行升级

  • 整包升级:适用于大版本更新,runtime发生变化时(模块、配置、版本等变化)必须使用此更新方法
  • 应用资源升级:适用于小版本更新 。runtime不变,前端页面整体压缩包更新
  • 应用资源差量升级:适用于小版本更新 。runtime不变,前端页面仅需要更新的部分更新。

本文重点描述5+应用整包升级,逻辑其实是非常简单,主要有三个步骤:

  1. 查询是否有新版本更新
  2. 下载新版本
  3. 安装新版本

而在实际应用的升级过程中则需要处理很多细节问题,下面就按照这个流程来简单说明在5+App中实现应用升级的逻辑。

查询是否有新版本更新

这个操作其实非常简单,就是客户端与升级服务器的一次交互操作,比较升级服务器上发布的最新客户端版本是否高于当前客户端版本号(5+ API中可以通过plus.runtime.version获取当前apk/ipa的版本号,注意打包方生效)?是的话则需要升级,否则无需升级。
从逻辑上来考虑有两种判断模式:

  1. 客户端判断是否有升级
    客户端从服务器获取最新的版本号,本地js判断是否需要升级。
  2. 服务器判断是否有升级
    客户端提交版本到服务器,有服务器判断返回是否需要升级。
    前者的优点是否服务器压力小,静态返回最新客户端版本即可,后者的优点则升级控制会更灵活,可以根据其它条件动态控制部分用户先升级(灰度发布)等。有条件的情况推荐采用第二种方式进行判断。

可以使用Javascript中的标准XHR请求,如果存在跨域问题则使用5+ API的XMLHttpRequest

下载新版本

如果判断到需要更新版本,则需要从服务器下载新版本,通常升级服务器应该返回下载新版本的地址(或者从固定的地址获取)。
有两种下载方法,一种调用Downloader API下载,示例如下:

var url=""; // 下载文件地址  
var dtask = plus.downloader.createDownload( url, {}, function ( d, status ) {  
    if ( status == 200 ) { // 下载成功  
        var path = d.filename;  
        console.log(d.filename);  
    } else {//下载失败  
        alert( "Download failed: " + status );   
    }    
});  
dtask.start(); 

安装新版本

下载原生安装包apk后,可调用[plus.runtime.install]()方法安装,示例如下:

    plus.runtime.install(path);  // 安装下载的apk文件

注意
iOS平台的ipa无法安装,此时需要跳转到appstore,提示用户自动点击升级更新,跳转到appstore的方法为打开应用的appstore地址,示例如下:

var url='itms-apps://itunes.apple.com/cn/app/hello-h5+/id682211190?l=zh&mt=8';// HelloH5应用在appstore的地址  
plus.runtime.openURL(url);

此处url是以"itms-apps://"开头,后面跟appstore上应用地址。

示例
在Hello H5+和Hello mui示例里,有2种不同的检查更新处理方式。
Hello H5+里的update.js比较复杂,在js里执行下载apk并安装的逻辑。
Hello mui里的update.js比较简单,弹出新包下载地址到浏览器,由浏览器执行下载逻辑。
如何选择看自己的要求。

继续阅读 »

官方已发布APP升级中心,支持原生APP整包升级和wgt资源包升级。详见

5+应用可使用以下方式进行升级

  • 整包升级:适用于大版本更新,runtime发生变化时(模块、配置、版本等变化)必须使用此更新方法
  • 应用资源升级:适用于小版本更新 。runtime不变,前端页面整体压缩包更新
  • 应用资源差量升级:适用于小版本更新 。runtime不变,前端页面仅需要更新的部分更新。

本文重点描述5+应用整包升级,逻辑其实是非常简单,主要有三个步骤:

  1. 查询是否有新版本更新
  2. 下载新版本
  3. 安装新版本

而在实际应用的升级过程中则需要处理很多细节问题,下面就按照这个流程来简单说明在5+App中实现应用升级的逻辑。

查询是否有新版本更新

这个操作其实非常简单,就是客户端与升级服务器的一次交互操作,比较升级服务器上发布的最新客户端版本是否高于当前客户端版本号(5+ API中可以通过plus.runtime.version获取当前apk/ipa的版本号,注意打包方生效)?是的话则需要升级,否则无需升级。
从逻辑上来考虑有两种判断模式:

  1. 客户端判断是否有升级
    客户端从服务器获取最新的版本号,本地js判断是否需要升级。
  2. 服务器判断是否有升级
    客户端提交版本到服务器,有服务器判断返回是否需要升级。
    前者的优点是否服务器压力小,静态返回最新客户端版本即可,后者的优点则升级控制会更灵活,可以根据其它条件动态控制部分用户先升级(灰度发布)等。有条件的情况推荐采用第二种方式进行判断。

可以使用Javascript中的标准XHR请求,如果存在跨域问题则使用5+ API的XMLHttpRequest

下载新版本

如果判断到需要更新版本,则需要从服务器下载新版本,通常升级服务器应该返回下载新版本的地址(或者从固定的地址获取)。
有两种下载方法,一种调用Downloader API下载,示例如下:

var url=""; // 下载文件地址  
var dtask = plus.downloader.createDownload( url, {}, function ( d, status ) {  
    if ( status == 200 ) { // 下载成功  
        var path = d.filename;  
        console.log(d.filename);  
    } else {//下载失败  
        alert( "Download failed: " + status );   
    }    
});  
dtask.start(); 

安装新版本

下载原生安装包apk后,可调用[plus.runtime.install]()方法安装,示例如下:

    plus.runtime.install(path);  // 安装下载的apk文件

注意
iOS平台的ipa无法安装,此时需要跳转到appstore,提示用户自动点击升级更新,跳转到appstore的方法为打开应用的appstore地址,示例如下:

var url='itms-apps://itunes.apple.com/cn/app/hello-h5+/id682211190?l=zh&mt=8';// HelloH5应用在appstore的地址  
plus.runtime.openURL(url);

此处url是以"itms-apps://"开头,后面跟appstore上应用地址。

示例
在Hello H5+和Hello mui示例里,有2种不同的检查更新处理方式。
Hello H5+里的update.js比较复杂,在js里执行下载apk并安装的逻辑。
Hello mui里的update.js比较简单,弹出新包下载地址到浏览器,由浏览器执行下载逻辑。
如何选择看自己的要求。

收起阅读 »

低价外包H5移动端页面

外包

纯切图,css3动画

纯切图,css3动画