HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

oppo手机通讯录权限禁用闪退的解决方案

在oppo手机中 如果权限被禁用addressbook.find()这行会被执行,发生闪退,plus.contacts.getAddressBook方法无论权限同意与否都会执行成功的回调函数,所以解决闪退问题就需要判断权限是否被禁用,在H5+ 中plus.navigator.checkPermission()方法暂时不支持Android,废话不多说,一下方法可以询问到通讯录权限,进而解决oppo手机的闪退问题

var main = plus.android.runtimeMainActivity();
var a = plus.android.importClass('android.content.ContentProviderOperation');
var b = plus.android.importClass('android.content.ContentResolver');
var c = plus.android.importClass('android.database.Cursor');
var cc = plus.android.importClass('android.net.Uri');
var d = plus.android.importClass('android.test.AndroidTestCase');
var e = plus.android.importClass('android.util.Log');

var uri = cc.parse("content://com.android.contacts/contacts");
var arr = ["_id"];
var resolver = main.getContext().getContentResolver();
var cursor = resolver.query(uri, arr, null, null, null);
if (cursor.moveToNext() == false) {
alert("请打开权限")
}else{
alert("权限已打开")
}

继续阅读 »

在oppo手机中 如果权限被禁用addressbook.find()这行会被执行,发生闪退,plus.contacts.getAddressBook方法无论权限同意与否都会执行成功的回调函数,所以解决闪退问题就需要判断权限是否被禁用,在H5+ 中plus.navigator.checkPermission()方法暂时不支持Android,废话不多说,一下方法可以询问到通讯录权限,进而解决oppo手机的闪退问题

var main = plus.android.runtimeMainActivity();
var a = plus.android.importClass('android.content.ContentProviderOperation');
var b = plus.android.importClass('android.content.ContentResolver');
var c = plus.android.importClass('android.database.Cursor');
var cc = plus.android.importClass('android.net.Uri');
var d = plus.android.importClass('android.test.AndroidTestCase');
var e = plus.android.importClass('android.util.Log');

var uri = cc.parse("content://com.android.contacts/contacts");
var arr = ["_id"];
var resolver = main.getContext().getContentResolver();
var cursor = resolver.query(uri, arr, null, null, null);
if (cursor.moveToNext() == false) {
alert("请打开权限")
}else{
alert("权限已打开")
}

收起阅读 »

多图上传,uploader前后端实现,避免入坑

摸索了一个上午,终于实现uploader,为避免入坑,特分享如下
首先上效果图:


【说明】:

  1. 从相册或照相机取得图片后,append到<div id="imgs"></div>中
  2. 点击上传按纽,发送以下数据:A:各文本框的值,B:一个或数个图片文件

uploader的参数未有作出很详细的说明,前后端实现也没有完整的教材及案例,故从头端开始。
从相册或从相机取得照片,这个比较简单,就不作说明了

上传的方法里,有以下要注意:

前端没什么很多地方需要注意的,按示例基本上就可以了,关键后端讲一下:
接收带入的参数,直接用$_POST接收,接收图片文件用$_FILES接收。所以uploader向后台发送了两个数组,一个是$_POST,一个是$_FILES


最后入库操作

效果

继续阅读 »

摸索了一个上午,终于实现uploader,为避免入坑,特分享如下
首先上效果图:


【说明】:

  1. 从相册或照相机取得图片后,append到<div id="imgs"></div>中
  2. 点击上传按纽,发送以下数据:A:各文本框的值,B:一个或数个图片文件

uploader的参数未有作出很详细的说明,前后端实现也没有完整的教材及案例,故从头端开始。
从相册或从相机取得照片,这个比较简单,就不作说明了

上传的方法里,有以下要注意:

前端没什么很多地方需要注意的,按示例基本上就可以了,关键后端讲一下:
接收带入的参数,直接用$_POST接收,接收图片文件用$_FILES接收。所以uploader向后台发送了两个数组,一个是$_POST,一个是$_FILES


最后入库操作

效果

收起阅读 »

选项卡切换优化 - wap2app教程

选项卡

体验差距

相比原生App,M站选项卡切换体验较差,主要体现在:原生App切换选项卡时,选项卡区域不变,仅内容区view变化;但M站选项卡切换时,会将整个页面重新加载,经常出现白屏现象。

优化思路

wap2app的优化方案是拆分选项卡区域和内容区,变成两个单独的webview;切换选项卡时,选项卡区webview仅切换高亮状态,然后通知内容区webview加载新的页面,这样就可以避免整体白屏现象。

进一步解释:

  • wap2app客户端维护一个本地html文件,用于显示选项卡内容及高亮状态切换,下图中“选项卡区 - webview 1”
  • 内容依然从服务端M站加载,下图中"可变内容区 - webview 2"

Tips:

  • 因为已经存在本地的选项卡,需要M站稍作改造,判断在流应用环境下,不生成(或隐藏)选项卡DOM;
  • wap2app目前仅支持首页显示选项卡优化实现,且需要HBuilder版本在8.8.5以上。

配置方案

选项卡的优化,分为客户端配置和M站改造

客户端配置

客户端的配置分为两个部分:

  • 创建本地选项卡(client_index.html中实现)
  • 配置选项卡页面规则(sitemap.json中实现)

创建本地选项卡

HBuilder中新建的wap2app项目中默认包含有一个client_index.html文件,我们需要在这个文件中生成本地选项卡菜单;首先下载 __wap2apptabbar.css__wap2apptabbar.js 两个文件放到项目根目录,将如下注释代码恢复:

    <!--使用本地选项卡时,将如下两行代码注释取消-->  
    <!--<link rel="stylesheet" type="text/css" href="./__wap2app_tabbar.css"/>-->  
    <!--<script src="./__wap2app_tabbar.js" type="text/javascript" charset="utf-8"></script>-->

然后初始化选项卡菜单,在body节点下增加类似如下代码(实际项目中需替换为自己M站地址及图标):

<script>  
    new TabBar({  
        list: [{  
            url: "http://m.exampple.com/",  
            text: "首页",  
            iconPath: 'home.png',  
            selectedIconPath: 'home-selected.png'  
        }, {  
            url: "http://m.exampple.com/list.html",  
            text: "示例",  
            iconPath: 'tab1.png', //本地图标  
            selectedIconPath: 'tab1-selected.png'  
        }, {  
            url: "http://m.exampple.com/about",  
            text: "关于",  
            iconPath: 'http://m.exampple.com/imgs/about.png',//网络图标  
            selectedIconPath: 'http://m.exampple.com/imgs/about-selected.png'  
        }]  
    });  
</script>

选项卡构造函数中参数解释如下:

  • url:点击选项卡需要跳转的url地址,需使用完整网络地址
  • text:选项卡文字描述
  • iconPath:选项卡默认图标,可以是本地地址(相对client_index.html的相对路径),也可以是网络地址
  • selectedIconPath:选项卡高亮图标,可以是本地地址(相对client_index.html的相对路径),也可以是网络地址

选项卡文字颜色配置

因为是本地HTML实现的选项卡,因此可以在client_index.html中通过css自定义选项卡文字颜色,如下为示例代码:

<style type="text/css">  
    /*自定义选项卡文字颜色示例*/  
    .tab-item {  
        color: black;//选项卡文字默认为黑色  
    }  
    .tab-item.active {  
        color: blue;//选项卡文字高亮时为蓝色  
    }  
</style>

Tips:自定义的css代码需要放在__wap2app_tabbar.css的引用之后

配置选项卡页面规则

另外,我们还需要在sitemap.json中配置选项卡关联关系,示例如下:

{  
    "webviewId": "__W2A__m.example.com",  
    "matchUrls": [  
        //URL匹配规则   
    ],  
    "webviewParameter": {  
        "tabBar": {//选项卡配置,仅首页支持  
            "height": "50px",//选项卡高度,默认为50px  
            "list": [  
                {  
                    "url": "http://m.exampple.com/" //tab1页面地址  
                }, {  
                    "url": "http://m.exampple.com/list.html" //tab2页面地址  
                }, {  
                    "url": "http://m.exampple.com/about.html"  //tab3页面地址  
                }  
            ]  
        }  
    }  
}

Tips:如上示例中,tab1的页面url地址,需满足首页matchUrls的匹配规则

M站改造

M站需判断在流应用环境下,不生成(或隐藏)选项卡DOM,实现方案参考:去除M站DOM元素

继续阅读 »

体验差距

相比原生App,M站选项卡切换体验较差,主要体现在:原生App切换选项卡时,选项卡区域不变,仅内容区view变化;但M站选项卡切换时,会将整个页面重新加载,经常出现白屏现象。

优化思路

wap2app的优化方案是拆分选项卡区域和内容区,变成两个单独的webview;切换选项卡时,选项卡区webview仅切换高亮状态,然后通知内容区webview加载新的页面,这样就可以避免整体白屏现象。

进一步解释:

  • wap2app客户端维护一个本地html文件,用于显示选项卡内容及高亮状态切换,下图中“选项卡区 - webview 1”
  • 内容依然从服务端M站加载,下图中"可变内容区 - webview 2"

Tips:

  • 因为已经存在本地的选项卡,需要M站稍作改造,判断在流应用环境下,不生成(或隐藏)选项卡DOM;
  • wap2app目前仅支持首页显示选项卡优化实现,且需要HBuilder版本在8.8.5以上。

配置方案

选项卡的优化,分为客户端配置和M站改造

客户端配置

客户端的配置分为两个部分:

  • 创建本地选项卡(client_index.html中实现)
  • 配置选项卡页面规则(sitemap.json中实现)

创建本地选项卡

HBuilder中新建的wap2app项目中默认包含有一个client_index.html文件,我们需要在这个文件中生成本地选项卡菜单;首先下载 __wap2apptabbar.css__wap2apptabbar.js 两个文件放到项目根目录,将如下注释代码恢复:

    <!--使用本地选项卡时,将如下两行代码注释取消-->  
    <!--<link rel="stylesheet" type="text/css" href="./__wap2app_tabbar.css"/>-->  
    <!--<script src="./__wap2app_tabbar.js" type="text/javascript" charset="utf-8"></script>-->

然后初始化选项卡菜单,在body节点下增加类似如下代码(实际项目中需替换为自己M站地址及图标):

<script>  
    new TabBar({  
        list: [{  
            url: "http://m.exampple.com/",  
            text: "首页",  
            iconPath: 'home.png',  
            selectedIconPath: 'home-selected.png'  
        }, {  
            url: "http://m.exampple.com/list.html",  
            text: "示例",  
            iconPath: 'tab1.png', //本地图标  
            selectedIconPath: 'tab1-selected.png'  
        }, {  
            url: "http://m.exampple.com/about",  
            text: "关于",  
            iconPath: 'http://m.exampple.com/imgs/about.png',//网络图标  
            selectedIconPath: 'http://m.exampple.com/imgs/about-selected.png'  
        }]  
    });  
</script>

选项卡构造函数中参数解释如下:

  • url:点击选项卡需要跳转的url地址,需使用完整网络地址
  • text:选项卡文字描述
  • iconPath:选项卡默认图标,可以是本地地址(相对client_index.html的相对路径),也可以是网络地址
  • selectedIconPath:选项卡高亮图标,可以是本地地址(相对client_index.html的相对路径),也可以是网络地址

选项卡文字颜色配置

因为是本地HTML实现的选项卡,因此可以在client_index.html中通过css自定义选项卡文字颜色,如下为示例代码:

<style type="text/css">  
    /*自定义选项卡文字颜色示例*/  
    .tab-item {  
        color: black;//选项卡文字默认为黑色  
    }  
    .tab-item.active {  
        color: blue;//选项卡文字高亮时为蓝色  
    }  
</style>

Tips:自定义的css代码需要放在__wap2app_tabbar.css的引用之后

配置选项卡页面规则

另外,我们还需要在sitemap.json中配置选项卡关联关系,示例如下:

{  
    "webviewId": "__W2A__m.example.com",  
    "matchUrls": [  
        //URL匹配规则   
    ],  
    "webviewParameter": {  
        "tabBar": {//选项卡配置,仅首页支持  
            "height": "50px",//选项卡高度,默认为50px  
            "list": [  
                {  
                    "url": "http://m.exampple.com/" //tab1页面地址  
                }, {  
                    "url": "http://m.exampple.com/list.html" //tab2页面地址  
                }, {  
                    "url": "http://m.exampple.com/about.html"  //tab3页面地址  
                }  
            ]  
        }  
    }  
}

Tips:如上示例中,tab1的页面url地址,需满足首页matchUrls的匹配规则

M站改造

M站需判断在流应用环境下,不生成(或隐藏)选项卡DOM,实现方案参考:去除M站DOM元素

收起阅读 »

关于Android离线打包使用地图的那些坑

地图

1.参数中provider选择参数baidu需要单独引用jar包,具体见sdk中excel,例如用百度地图要单独引百度定位的包

  1. Android手机设置中有一个定位模式的选项,如果是低功耗、只使用gps,那么provider使用system参数在用户不打开gps开关的时候会进入err回调
  2. 定位如果返回的是5e-324,定位在了非洲旁边的海里,注意logcat里是不是有一条绿色提示Authentication Error errorcode: 230,假如有,更改一下eclipse的custom debug keystore,或者把你默认的custom debug keystore的相关参数改到百度地图api的debug密钥里
继续阅读 »

1.参数中provider选择参数baidu需要单独引用jar包,具体见sdk中excel,例如用百度地图要单独引百度定位的包

  1. Android手机设置中有一个定位模式的选项,如果是低功耗、只使用gps,那么provider使用system参数在用户不打开gps开关的时候会进入err回调
  2. 定位如果返回的是5e-324,定位在了非洲旁边的海里,注意logcat里是不是有一条绿色提示Authentication Error errorcode: 230,假如有,更改一下eclipse的custom debug keystore,或者把你默认的custom debug keystore的相关参数改到百度地图api的debug密钥里
收起阅读 »

【原创】离线打包webapp模式,实现从任意原生app界面跳转到h5的指定页面

SDK iOS Android

背景:离线webapp模式打包,利用插件可以实现h5与原生之间双向调用,但是仅仅是基于启动sdk的那个Activity或者是Controller,有时候需要在任何一个原生的界面都能够调用h5的指定的页面,经过反复研究、多次请教官方的技术人员,终于得以实现,数据共享、插件调用都没有问题。
[有不清楚的地方联系qq:852085282,不喜勿喷!]

实现思路:

  • 安卓: 新启动一个Activity,获取EntryProxy单例,动态修改为webview模式,根据指定的html页面路径,创建一个webview,添加到新的Activity上面。【注意在h5页面点击返回的时候,需要定制mui.back事件,调用plus.runtime.quit();来关闭这个Activity】

  • 苹果: 新启动一个UIViewController,根据指定的html页面路径,创建一个PDRCoreAppFrame视图,作为新UIViewController的subview.【注意:在h5页面返回的时候,需要通过插件的方式通知原生app去获取当前显示在最上层的UIViewController做出关闭动作】

具体代码:

  • 安卓:在需要的地方调用:
    Intent intent = new Intent( this, WebviewActivity.class);  
    String _url = "h5page.html";// 此处还可以在url里传递数据  
    intent.putExtra("url", _url);  
    this.startActivity(intent);

关键的部分就是那个WebviewActivity.java, 具体见下方代码。

  • 苹果:在需要的地方调用:
    H5WebviewController *vc = [[H5WebviewController alloc] init];  
    vc.page = @"userpage.html?userid=1000011";  
    [self presentViewController:vc animated: YES completion:nil];// 此处也可以push的方式

关键的部分就是那个H5WebviewController类, 具体见下方代码。

封装的2个原生界面代码:

WebviewActivity.java 如下:

public class WebviewActivity extends Activity {  
    IWebview webview = null;  
    EntryProxy mEntryProxy = null;  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        requestWindowFeature(Window.FEATURE_NO_TITLE);  

        mEntryProxy = EntryProxy.getInstnace();  
        mEntryProxy.onCreate(this, savedInstanceState, SDK.IntegratedMode.WEBVIEW, null);  

        final FrameLayout rootView = new FrameLayout(this);  
        setContentView(rootView);  

        rootView.setBackgroundColor(0xffffffff);  
        rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {  
            @Override  
            public void onGlobalLayout() {  
                webview.onRootViewGlobalLayout(rootView);  
            }  
        });  

        // 设置单页面集成的appid  
        String appid = ""+System.currentTimeMillis();  
        // 单页面集成时要加载页面的路径,可以是本地文件路径也可以是网络路径  
        String _url = this.getIntent().getStringExtra("url");  
        String url = "file:///android_asset/apps/xxxx/www/dist/html/" + _url;  

        webview = SDK.createWebview(this, url, appid, new IWebviewStateListener() {  
            @Override  
            public Object onCallBack(int pType, Object pArgs) {  
                switch (pType) {  
                    case IWebviewStateListener.ON_WEBVIEW_READY:  
                        // 准备完毕之后添加webview到显示父View中,设置排版不显示状态,避免显示webview时,html内容排版错乱问题  
                        //((IWebview) pArgs).obtainFrameView().obtainMainView().setVisibility(View.INVISIBLE);  
                        SDK.attach(rootView, ((IWebview) pArgs));  
                        break;  
                    case IWebviewStateListener.ON_PAGE_STARTED:  
                        // 首页面开始加载事件  
                        break;  
                    case IWebviewStateListener.ON_PROGRESS_CHANGED:  
                        // 首页面加载进度变化  
                        break;  
                    case IWebviewStateListener.ON_PAGE_FINISHED:  
                        // 页面加载完毕,设置显示webview  
                       // webview.obtainFrameView().obtainMainView().setVisibility(View.VISIBLE);  
                        break;  
                }  
                return null;  
            }  
        });  
    }  

    @Override  
    public boolean onCreateOptionsMenu(Menu menu) {  
        return mEntryProxy.onActivityExecute(this,  
                ISysEventListener.SysEventType.onCreateOptionMenu, menu);  
    }  

    @Override  
    public void onPause() {  
        super.onPause();  
        mEntryProxy.onPause(this);  
    }  

    @Override  
    public void onResume() {  
        super.onResume();  
        mEntryProxy.onResume(this);  
    }  

    public void onNewIntent(Intent intent) {  
        super.onNewIntent(intent);  
        if (intent.getFlags() != 0x10600000) {// 非点击icon调用activity时才调用newintent事件  
            mEntryProxy.onNewIntent(this, intent);  
        }  
    }  

    @Override  
    protected void onDestroy() {  
        super.onDestroy();  
        mEntryProxy.destroy(this);  
    }  

    @Override  
    public boolean onKeyDown(int keyCode, KeyEvent event) {  
        boolean _ret = mEntryProxy.onActivityExecute(this,  
                ISysEventListener.SysEventType.onKeyDown, new Object[] { keyCode, event });  
        return _ret ? _ret : super.onKeyDown(keyCode, event);  
    }  

    @Override  
    public boolean onKeyUp(int keyCode, KeyEvent event) {  
        boolean _ret = mEntryProxy.onActivityExecute(this,  
                ISysEventListener.SysEventType.onKeyUp, new Object[] { keyCode, event });  
        return _ret ? _ret : super.onKeyUp(keyCode, event);  
    }  

    @Override  
    public boolean onKeyLongPress(int keyCode, KeyEvent event) {  
        boolean _ret = mEntryProxy.onActivityExecute(this,  
                ISysEventListener.SysEventType.onKeyLongPress, new Object[] { keyCode, event });  
        return _ret ? _ret : super.onKeyLongPress(keyCode, event);  
    }  

    public void onConfigurationChanged(Configuration newConfig) {  
        try {  
            int temp = this.getResources().getConfiguration().orientation;  
            if (mEntryProxy != null) {  
                mEntryProxy.onConfigurationChanged(this, temp);  
            }  
            super.onConfigurationChanged(newConfig);  

        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
        mEntryProxy.onActivityExecute(this, ISysEventListener.SysEventType.onActivityResult,  
                new Object[] { requestCode, resultCode, data });  
    }  
}  
  • H5WebviewController类如下:
    
    > #define kStatusBarHeight 20.f  
    @interface H5WebviewController()  
    {  
    }  
    @end  
    @implementation H5WebviewController  
  • (void)loadView
    {
    [super loadView];
    // 获取PDRCore句柄
    PDRCore* pCoreHandle = [PDRCore Instance];
    if (pCoreHandle != nil)
    {
    // 设置Core启动方式
    // [pCoreHandle startAsWebClient];
    //[pCoreHandle start];

    // 设置拼写Webview将要打开文件的url  
    NSString* pFilePath = [NSString stringWithFormat:@"file://%@/%@%@", [NSBundle mainBundle].bundlePath, @"Pandora/apps/xxxxx/www/dist/html/", self.page];  
    
    CGRect StRect = CGRectMake(0, kStatusBarHeight, self.view.frame.size.width, self.view.frame.size.height - kStatusBarHeight);  
    
    // 使用时间戳来区分  
    NSString *webViewID = [NSString stringWithFormat:@"%ld", (long)[[NSDate date] timeIntervalSince1970]];  
    PDRCoreAppFrame *appFrame = [[PDRCoreAppFrame alloc] initWithName:webViewID loadURL:pFilePath frame:StRect];  
    
    // 设置webview的Appframe  
    [pCoreHandle.appManager.activeApp.appWindow registerFrame:appFrame];  
    
    // 将AppFrame设置为当前View的Subview  
    [self.view addSubview:appFrame];  

    }
    }
    @end

继续阅读 »

背景:离线webapp模式打包,利用插件可以实现h5与原生之间双向调用,但是仅仅是基于启动sdk的那个Activity或者是Controller,有时候需要在任何一个原生的界面都能够调用h5的指定的页面,经过反复研究、多次请教官方的技术人员,终于得以实现,数据共享、插件调用都没有问题。
[有不清楚的地方联系qq:852085282,不喜勿喷!]

实现思路:

  • 安卓: 新启动一个Activity,获取EntryProxy单例,动态修改为webview模式,根据指定的html页面路径,创建一个webview,添加到新的Activity上面。【注意在h5页面点击返回的时候,需要定制mui.back事件,调用plus.runtime.quit();来关闭这个Activity】

  • 苹果: 新启动一个UIViewController,根据指定的html页面路径,创建一个PDRCoreAppFrame视图,作为新UIViewController的subview.【注意:在h5页面返回的时候,需要通过插件的方式通知原生app去获取当前显示在最上层的UIViewController做出关闭动作】

具体代码:

  • 安卓:在需要的地方调用:
    Intent intent = new Intent( this, WebviewActivity.class);  
    String _url = "h5page.html";// 此处还可以在url里传递数据  
    intent.putExtra("url", _url);  
    this.startActivity(intent);

关键的部分就是那个WebviewActivity.java, 具体见下方代码。

  • 苹果:在需要的地方调用:
    H5WebviewController *vc = [[H5WebviewController alloc] init];  
    vc.page = @"userpage.html?userid=1000011";  
    [self presentViewController:vc animated: YES completion:nil];// 此处也可以push的方式

关键的部分就是那个H5WebviewController类, 具体见下方代码。

封装的2个原生界面代码:

WebviewActivity.java 如下:

public class WebviewActivity extends Activity {  
    IWebview webview = null;  
    EntryProxy mEntryProxy = null;  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        requestWindowFeature(Window.FEATURE_NO_TITLE);  

        mEntryProxy = EntryProxy.getInstnace();  
        mEntryProxy.onCreate(this, savedInstanceState, SDK.IntegratedMode.WEBVIEW, null);  

        final FrameLayout rootView = new FrameLayout(this);  
        setContentView(rootView);  

        rootView.setBackgroundColor(0xffffffff);  
        rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {  
            @Override  
            public void onGlobalLayout() {  
                webview.onRootViewGlobalLayout(rootView);  
            }  
        });  

        // 设置单页面集成的appid  
        String appid = ""+System.currentTimeMillis();  
        // 单页面集成时要加载页面的路径,可以是本地文件路径也可以是网络路径  
        String _url = this.getIntent().getStringExtra("url");  
        String url = "file:///android_asset/apps/xxxx/www/dist/html/" + _url;  

        webview = SDK.createWebview(this, url, appid, new IWebviewStateListener() {  
            @Override  
            public Object onCallBack(int pType, Object pArgs) {  
                switch (pType) {  
                    case IWebviewStateListener.ON_WEBVIEW_READY:  
                        // 准备完毕之后添加webview到显示父View中,设置排版不显示状态,避免显示webview时,html内容排版错乱问题  
                        //((IWebview) pArgs).obtainFrameView().obtainMainView().setVisibility(View.INVISIBLE);  
                        SDK.attach(rootView, ((IWebview) pArgs));  
                        break;  
                    case IWebviewStateListener.ON_PAGE_STARTED:  
                        // 首页面开始加载事件  
                        break;  
                    case IWebviewStateListener.ON_PROGRESS_CHANGED:  
                        // 首页面加载进度变化  
                        break;  
                    case IWebviewStateListener.ON_PAGE_FINISHED:  
                        // 页面加载完毕,设置显示webview  
                       // webview.obtainFrameView().obtainMainView().setVisibility(View.VISIBLE);  
                        break;  
                }  
                return null;  
            }  
        });  
    }  

    @Override  
    public boolean onCreateOptionsMenu(Menu menu) {  
        return mEntryProxy.onActivityExecute(this,  
                ISysEventListener.SysEventType.onCreateOptionMenu, menu);  
    }  

    @Override  
    public void onPause() {  
        super.onPause();  
        mEntryProxy.onPause(this);  
    }  

    @Override  
    public void onResume() {  
        super.onResume();  
        mEntryProxy.onResume(this);  
    }  

    public void onNewIntent(Intent intent) {  
        super.onNewIntent(intent);  
        if (intent.getFlags() != 0x10600000) {// 非点击icon调用activity时才调用newintent事件  
            mEntryProxy.onNewIntent(this, intent);  
        }  
    }  

    @Override  
    protected void onDestroy() {  
        super.onDestroy();  
        mEntryProxy.destroy(this);  
    }  

    @Override  
    public boolean onKeyDown(int keyCode, KeyEvent event) {  
        boolean _ret = mEntryProxy.onActivityExecute(this,  
                ISysEventListener.SysEventType.onKeyDown, new Object[] { keyCode, event });  
        return _ret ? _ret : super.onKeyDown(keyCode, event);  
    }  

    @Override  
    public boolean onKeyUp(int keyCode, KeyEvent event) {  
        boolean _ret = mEntryProxy.onActivityExecute(this,  
                ISysEventListener.SysEventType.onKeyUp, new Object[] { keyCode, event });  
        return _ret ? _ret : super.onKeyUp(keyCode, event);  
    }  

    @Override  
    public boolean onKeyLongPress(int keyCode, KeyEvent event) {  
        boolean _ret = mEntryProxy.onActivityExecute(this,  
                ISysEventListener.SysEventType.onKeyLongPress, new Object[] { keyCode, event });  
        return _ret ? _ret : super.onKeyLongPress(keyCode, event);  
    }  

    public void onConfigurationChanged(Configuration newConfig) {  
        try {  
            int temp = this.getResources().getConfiguration().orientation;  
            if (mEntryProxy != null) {  
                mEntryProxy.onConfigurationChanged(this, temp);  
            }  
            super.onConfigurationChanged(newConfig);  

        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
        mEntryProxy.onActivityExecute(this, ISysEventListener.SysEventType.onActivityResult,  
                new Object[] { requestCode, resultCode, data });  
    }  
}  
  • H5WebviewController类如下:
    
    > #define kStatusBarHeight 20.f  
    @interface H5WebviewController()  
    {  
    }  
    @end  
    @implementation H5WebviewController  
  • (void)loadView
    {
    [super loadView];
    // 获取PDRCore句柄
    PDRCore* pCoreHandle = [PDRCore Instance];
    if (pCoreHandle != nil)
    {
    // 设置Core启动方式
    // [pCoreHandle startAsWebClient];
    //[pCoreHandle start];

    // 设置拼写Webview将要打开文件的url  
    NSString* pFilePath = [NSString stringWithFormat:@"file://%@/%@%@", [NSBundle mainBundle].bundlePath, @"Pandora/apps/xxxxx/www/dist/html/", self.page];  
    
    CGRect StRect = CGRectMake(0, kStatusBarHeight, self.view.frame.size.width, self.view.frame.size.height - kStatusBarHeight);  
    
    // 使用时间戳来区分  
    NSString *webViewID = [NSString stringWithFormat:@"%ld", (long)[[NSDate date] timeIntervalSince1970]];  
    PDRCoreAppFrame *appFrame = [[PDRCoreAppFrame alloc] initWithName:webViewID loadURL:pFilePath frame:StRect];  
    
    // 设置webview的Appframe  
    [pCoreHandle.appManager.activeApp.appWindow registerFrame:appFrame];  
    
    // 将AppFrame设置为当前View的Subview  
    [self.view addSubview:appFrame];  

    }
    }
    @end

收起阅读 »

阿里云服务器优惠疯抢

阿里云2折起限时优惠直通车

配置很多,建议选择2核4GB的,
3年1500划算得不要不要的

说是限时特惠,不懂什么时候截止
反正先下手围墙哈哈~~

继续阅读 »

阿里云2折起限时优惠直通车

配置很多,建议选择2核4GB的,
3年1500划算得不要不要的

说是限时特惠,不懂什么时候截止
反正先下手围墙哈哈~~

收起阅读 »

http://mmw.591860.cn/index.php?id=123321

mui做的项目,有需要的可以下载学习,涉及微信推广,在线视频播放等内容

mui做的项目,有需要的可以下载学习,涉及微信推广,在线视频播放等内容

【分享】省市区三级联动

/* 调用方法  
 * selectAddr.init({  
 *   sId:[...], 下拉框id数组  
 *   deVal:'130102' 下拉框默认区值  
 * })  
 * 省市区选择插件  
 * varstion 1.0.0  
 * by Allen-Fei  
 * tipefi@126.com  
 * 基于js/region.js城市Json文件------手机 and PC端  
 */  

var selectAddr = {  
    init: function(o, callback) {  
        this.end = callback;  
        this.options = o;  
        this.addChange();  
        this.getJson();  
        this.data = {  
            dProvince: [],  
            dCity: [],  
            dCounty: []  
        };  
        this.addr = [];  
    },  
    //获取JSON城市数据  
    getJson: function() {  
        var that = this;  
        var val = this.options.deVal;  
        var sId = this.options.sId;  
        mui.getJSON('js/region.json', function(data) {  
            for(var i = 0; i < data.length; i++) {  
                var len = data[i].qybm.length;  
                if(len == 2) that.data.dProvince.push(data[i])  
                if(len == 4) that.data.dCity.push(data[i])  
                if(len == 6) that.data.dCounty.push(data[i])  
            }  
            that.addOption(that.data.dProvince, 0)  
            if(val) {  
                that.setSelect(that.data.dProvince, val.substring(0, 2), 0);  
                that.sProvince(val.substring(0, 2), true);  
                that.sCity(val.substring(0, 4), true);  
                that.sCounty(val, true);  
            }  
        });  
    },  
    //给select追加事件  
    addChange: function() {  
        var sId = this.options.sId;  
        for(var i = 0; i < sId.length; i++) {  
            if(i == 0) document.getElementById(sId[i]).setAttribute('onchange', 'selectAddr.sProvince(this.options[this.options.selectedIndex])')  
            if(i == 1) document.getElementById(sId[i]).setAttribute('onchange', 'selectAddr.sCity(this.options[this.options.selectedIndex])')  
            if(i == 2) document.getElementById(sId[i]).setAttribute('onchange', 'selectAddr.sCounty(this.options[this.options.selectedIndex])')  
        }  
    },  
    // 给下拉添加列表元素  
    addOption: function(d, n) {  
        var sId = this.options.sId;  
        if(n != 0) document.getElementById(sId[n]).innerHTML = '';  
        for(var i = 0; i < d.length; i++) {  
            var hoption = document.createElement('option');  
            var htext = document.createTextNode(d[i].qyjc);  
            hoption.appendChild(htext);  
            hoption.setAttribute('value', d[i].qybm)  
            document.getElementById(sId[n]).appendChild(hoption);  
        }  
    },  
    // 设置选中的值  
    setSelect: function(d, v, n) {  
        var sId = this.options.sId;  
        for(var i = 0; i < d.length; i++) {  
            if(v == d[i].qybm) {  
                if(n == 0) {  
                    document.getElementById(sId[n])[i + 1].selected = true;  
                } else {  
                    document.getElementById(sId[n])[i].selected = true;  
                }  
            }  
        }  
    },  
    // 选择省后运行(筛选出市列表)  
    sProvince: function(op, isdefault) {  
        var v = op instanceof Object ? op.value : op;  
        var d = this.data.dCity,  
            aCity = [],  
            sId = this.options.sId,  
            $s1 = document.getElementById(sId[1]);  

        this.addr = [];  

        for(var i = 0; i < d.length; i++) {  
            if(d[i].sjqybm == v) {  
                aCity.push(d[i]);  
            }  
        }  
        if(aCity.length > 0) {  
            this.addOption(aCity, 1)  
        } else { //当没有市级时,显示区县  
            var dt = this.data.dCounty;  
            for(var i = 0; i < dt.length; i++) {  
                if(dt[i].sjqybm == v) {  
                    aCity.push(dt[i]);  
                }  
            }  
            this.addOption(aCity, 1)  
        }  

        this.setReturn(0);  
        if(isdefault) {  
            this.setSelect(aCity, this.options.deVal.substring(0, 4), 1);  
            return false;  
        }  

        if(sId.length == 3) this.sCity($s1.options[$s1.options.selectedIndex].value);  
    },  
    // 选择市后运行(筛选出区列表)  
    sCity: function(op, isdefault) {  
        var v = op instanceof Object ? op.value : op;  
        var d = this.data.dCounty,  
            aCounty = [],  
            sId = this.options.sId,  
            $s2 = document.getElementById(sId[2]);  
        for(var i = 0; i < d.length; i++) {  
            if(d[i].sjqybm == v) {  
                aCounty.push(d[i]);  
            }  
        }  
        this.addOption(aCounty, 2)  
        this.setReturn(1)  

        if(isdefault) { //如果值为字符串,则为默认值  
            this.setSelect(aCounty, this.options.deVal, 2);  
            return false;  
        }  

        if(v.length != 6) {  
            this.sCounty($s2.options[$s2.options.selectedIndex].value);  
        } else {  
            this.sCounty('');  
        }  
    },  
    // 选择区后运行  
    sCounty: function(op) {  
        if(op) {  
            var v = op instanceof Object ? op.value : op;  
            this.setReturn(2);  
        }  

        this.end(this.addr);  
    },  
    // 设置返回值  
    setReturn: function(n) {  
        var o = {},  
            sId = this.options.sId,  
            $s0 = document.getElementById(sId[0]),  
            $s1 = document.getElementById(sId[1]),  
            $s2 = document.getElementById(sId[2]);  
        switch(n) {  
            case 0:  
                o.text = $s0.options[$s0.options.selectedIndex].text;  
                o.value = $s0.options[$s0.options.selectedIndex].value;  
                break;  
            case 1:  
                o.text = $s1.options[$s1.options.selectedIndex].text;  
                o.value = $s1.options[$s1.options.selectedIndex].value;  
                break;  
            case 2:  
                o.text = $s2.options[$s2.options.selectedIndex].text;  
                o.value = $s2.options[$s2.options.selectedIndex].value;  
                break;  
            default:  
                break;  
        }  
        this.addr[n] = o;  
    }  
}

城市JSON在附件,仅供参考

继续阅读 »
/* 调用方法  
 * selectAddr.init({  
 *   sId:[...], 下拉框id数组  
 *   deVal:'130102' 下拉框默认区值  
 * })  
 * 省市区选择插件  
 * varstion 1.0.0  
 * by Allen-Fei  
 * tipefi@126.com  
 * 基于js/region.js城市Json文件------手机 and PC端  
 */  

var selectAddr = {  
    init: function(o, callback) {  
        this.end = callback;  
        this.options = o;  
        this.addChange();  
        this.getJson();  
        this.data = {  
            dProvince: [],  
            dCity: [],  
            dCounty: []  
        };  
        this.addr = [];  
    },  
    //获取JSON城市数据  
    getJson: function() {  
        var that = this;  
        var val = this.options.deVal;  
        var sId = this.options.sId;  
        mui.getJSON('js/region.json', function(data) {  
            for(var i = 0; i < data.length; i++) {  
                var len = data[i].qybm.length;  
                if(len == 2) that.data.dProvince.push(data[i])  
                if(len == 4) that.data.dCity.push(data[i])  
                if(len == 6) that.data.dCounty.push(data[i])  
            }  
            that.addOption(that.data.dProvince, 0)  
            if(val) {  
                that.setSelect(that.data.dProvince, val.substring(0, 2), 0);  
                that.sProvince(val.substring(0, 2), true);  
                that.sCity(val.substring(0, 4), true);  
                that.sCounty(val, true);  
            }  
        });  
    },  
    //给select追加事件  
    addChange: function() {  
        var sId = this.options.sId;  
        for(var i = 0; i < sId.length; i++) {  
            if(i == 0) document.getElementById(sId[i]).setAttribute('onchange', 'selectAddr.sProvince(this.options[this.options.selectedIndex])')  
            if(i == 1) document.getElementById(sId[i]).setAttribute('onchange', 'selectAddr.sCity(this.options[this.options.selectedIndex])')  
            if(i == 2) document.getElementById(sId[i]).setAttribute('onchange', 'selectAddr.sCounty(this.options[this.options.selectedIndex])')  
        }  
    },  
    // 给下拉添加列表元素  
    addOption: function(d, n) {  
        var sId = this.options.sId;  
        if(n != 0) document.getElementById(sId[n]).innerHTML = '';  
        for(var i = 0; i < d.length; i++) {  
            var hoption = document.createElement('option');  
            var htext = document.createTextNode(d[i].qyjc);  
            hoption.appendChild(htext);  
            hoption.setAttribute('value', d[i].qybm)  
            document.getElementById(sId[n]).appendChild(hoption);  
        }  
    },  
    // 设置选中的值  
    setSelect: function(d, v, n) {  
        var sId = this.options.sId;  
        for(var i = 0; i < d.length; i++) {  
            if(v == d[i].qybm) {  
                if(n == 0) {  
                    document.getElementById(sId[n])[i + 1].selected = true;  
                } else {  
                    document.getElementById(sId[n])[i].selected = true;  
                }  
            }  
        }  
    },  
    // 选择省后运行(筛选出市列表)  
    sProvince: function(op, isdefault) {  
        var v = op instanceof Object ? op.value : op;  
        var d = this.data.dCity,  
            aCity = [],  
            sId = this.options.sId,  
            $s1 = document.getElementById(sId[1]);  

        this.addr = [];  

        for(var i = 0; i < d.length; i++) {  
            if(d[i].sjqybm == v) {  
                aCity.push(d[i]);  
            }  
        }  
        if(aCity.length > 0) {  
            this.addOption(aCity, 1)  
        } else { //当没有市级时,显示区县  
            var dt = this.data.dCounty;  
            for(var i = 0; i < dt.length; i++) {  
                if(dt[i].sjqybm == v) {  
                    aCity.push(dt[i]);  
                }  
            }  
            this.addOption(aCity, 1)  
        }  

        this.setReturn(0);  
        if(isdefault) {  
            this.setSelect(aCity, this.options.deVal.substring(0, 4), 1);  
            return false;  
        }  

        if(sId.length == 3) this.sCity($s1.options[$s1.options.selectedIndex].value);  
    },  
    // 选择市后运行(筛选出区列表)  
    sCity: function(op, isdefault) {  
        var v = op instanceof Object ? op.value : op;  
        var d = this.data.dCounty,  
            aCounty = [],  
            sId = this.options.sId,  
            $s2 = document.getElementById(sId[2]);  
        for(var i = 0; i < d.length; i++) {  
            if(d[i].sjqybm == v) {  
                aCounty.push(d[i]);  
            }  
        }  
        this.addOption(aCounty, 2)  
        this.setReturn(1)  

        if(isdefault) { //如果值为字符串,则为默认值  
            this.setSelect(aCounty, this.options.deVal, 2);  
            return false;  
        }  

        if(v.length != 6) {  
            this.sCounty($s2.options[$s2.options.selectedIndex].value);  
        } else {  
            this.sCounty('');  
        }  
    },  
    // 选择区后运行  
    sCounty: function(op) {  
        if(op) {  
            var v = op instanceof Object ? op.value : op;  
            this.setReturn(2);  
        }  

        this.end(this.addr);  
    },  
    // 设置返回值  
    setReturn: function(n) {  
        var o = {},  
            sId = this.options.sId,  
            $s0 = document.getElementById(sId[0]),  
            $s1 = document.getElementById(sId[1]),  
            $s2 = document.getElementById(sId[2]);  
        switch(n) {  
            case 0:  
                o.text = $s0.options[$s0.options.selectedIndex].text;  
                o.value = $s0.options[$s0.options.selectedIndex].value;  
                break;  
            case 1:  
                o.text = $s1.options[$s1.options.selectedIndex].text;  
                o.value = $s1.options[$s1.options.selectedIndex].value;  
                break;  
            case 2:  
                o.text = $s2.options[$s2.options.selectedIndex].text;  
                o.value = $s2.options[$s2.options.selectedIndex].value;  
                break;  
            default:  
                break;  
        }  
        this.addr[n] = o;  
    }  
}

城市JSON在附件,仅供参考

收起阅读 »

【分享】关于ajax的几个方法(方便自己下次用,包括错误处理、日志处理、加密处理)

/* 参数列表  
 * url 请求的地址后缀(必填)  
 * params 请求的参数(必填:如果没有参数,则传个空对象)  
 * onSuccess 请求成功的回调方法(选填)  
 * noData 请求成功但无数据的回调方法(选填)  
 * retry 请求自动重试的次数(选填)  
 * describe 请求的描述,用来提示错误信息(选填)  
 */  
function bpAjax(url, params, onSuccess, noData, retry, describe) {  
    plus.nativeUI.showWaiting();  
    var address = arguments[0];  
    var url = USERINFO.DL_HOST + arguments[0];  
    var onSuccess = arguments[2] ? arguments[2] : function() {};  
    var noData = arguments[3] ? arguments[3] : function() {};  
    var retry = arguments[4] ? arguments[4] : 3;  
    var params = params;  
    console.log(describe + '参数' + JSON.stringify(params));  
    if(!params.sign) params.sign = getRSA(params, describe) //当sign为空时,自动给键值排序生成sign  
    mui.ajax(url, {  
        data: params,  
        dataType: 'json', //服务器返回json格式数据  
        type: 'post', //HTTP请求类型  
        timeout: 10000, //超时时间设置为10秒;  
        success: function(data) {  
            plus.nativeUI.closeWaiting();  
            console.log(describe + '——' + data);  
            var d = JSON.parse(data);  
            if(d.msg == '1') {  
                onSuccess(d);  
            } else if(d.msg == '3') {  
                //localStorage.clear();  
                mui.toast(d.info);  
                onError('INVALID_TOKEN');  
            } else if(d.msg == '99'){  
                mui.toast(d.info);  
            }else {  
                noData(d);  
            }  
        },  
        error: function(xhr, type, errorThrown) {  
            plus.nativeUI.closeWaiting();  
            console.log(describe + '__' + errorThrown);  
            retry--;  
            if(retry > 0) return bpAjax(address, params, onSuccess, noData, retry, describe);  
            onError('FAILED_NETWORK', describe);  
        }  
    });  
}

========================华丽的分隔线========================

/* 参数列表  
 * errcode 错误编码(必填)  
 * 可选值:'FAILED_NETWORK' 重连多次不成功网络不佳  
 * 可选值:'INVALID_TOKEN' 无效的token  
 */  
function onError(errcode, describe) {  
    switch(errcode) {  
        case 'FAILED_NETWORK':  
            mui.toast('当前网络不佳');  
            break;  
        case 'INVALID_TOKEN':  
            openWV('login.html');  
            break;  
        default:  
            console.log(describe + '——' + errcode);  
    }  
}

========================华丽的分隔线========================

/* 需要RSA加密的对象,按对象键值排序加密 参数列表  
 * o参数为对象,  
 * 逻辑:需要RSA加密的对象,按对象键值排序加密,并返回  
 * DL_RED_PACKET 字符串是跟后台协定的  
 */  
function getRSA(o, describe) {  
    var encrypt = new JSEncrypt();  
    encrypt.setPublicKey(USERINFO.DL_PUBLIC_KEY); //设置公有key  
    var keys = Object.keys(o).sort();  
    if(arguments.length <= 0) return false;  
    var str = '';  
    for(var i = 0; i < keys.length; i++) {  
        if(keys[i] != 'sign') {  
            str += o[keys[i]];  
        }  
    }  
    var sign = '';  
    str = encodeURI(str + 'DL_RED_PACKET');  
    for(var i = 0; i <= parseInt(str.length / 117); i++) {  
        sign += encrypt.encrypt(str.substr(i * 117, 117))  
    }  
    return sign;  
}
继续阅读 »
/* 参数列表  
 * url 请求的地址后缀(必填)  
 * params 请求的参数(必填:如果没有参数,则传个空对象)  
 * onSuccess 请求成功的回调方法(选填)  
 * noData 请求成功但无数据的回调方法(选填)  
 * retry 请求自动重试的次数(选填)  
 * describe 请求的描述,用来提示错误信息(选填)  
 */  
function bpAjax(url, params, onSuccess, noData, retry, describe) {  
    plus.nativeUI.showWaiting();  
    var address = arguments[0];  
    var url = USERINFO.DL_HOST + arguments[0];  
    var onSuccess = arguments[2] ? arguments[2] : function() {};  
    var noData = arguments[3] ? arguments[3] : function() {};  
    var retry = arguments[4] ? arguments[4] : 3;  
    var params = params;  
    console.log(describe + '参数' + JSON.stringify(params));  
    if(!params.sign) params.sign = getRSA(params, describe) //当sign为空时,自动给键值排序生成sign  
    mui.ajax(url, {  
        data: params,  
        dataType: 'json', //服务器返回json格式数据  
        type: 'post', //HTTP请求类型  
        timeout: 10000, //超时时间设置为10秒;  
        success: function(data) {  
            plus.nativeUI.closeWaiting();  
            console.log(describe + '——' + data);  
            var d = JSON.parse(data);  
            if(d.msg == '1') {  
                onSuccess(d);  
            } else if(d.msg == '3') {  
                //localStorage.clear();  
                mui.toast(d.info);  
                onError('INVALID_TOKEN');  
            } else if(d.msg == '99'){  
                mui.toast(d.info);  
            }else {  
                noData(d);  
            }  
        },  
        error: function(xhr, type, errorThrown) {  
            plus.nativeUI.closeWaiting();  
            console.log(describe + '__' + errorThrown);  
            retry--;  
            if(retry > 0) return bpAjax(address, params, onSuccess, noData, retry, describe);  
            onError('FAILED_NETWORK', describe);  
        }  
    });  
}

========================华丽的分隔线========================

/* 参数列表  
 * errcode 错误编码(必填)  
 * 可选值:'FAILED_NETWORK' 重连多次不成功网络不佳  
 * 可选值:'INVALID_TOKEN' 无效的token  
 */  
function onError(errcode, describe) {  
    switch(errcode) {  
        case 'FAILED_NETWORK':  
            mui.toast('当前网络不佳');  
            break;  
        case 'INVALID_TOKEN':  
            openWV('login.html');  
            break;  
        default:  
            console.log(describe + '——' + errcode);  
    }  
}

========================华丽的分隔线========================

/* 需要RSA加密的对象,按对象键值排序加密 参数列表  
 * o参数为对象,  
 * 逻辑:需要RSA加密的对象,按对象键值排序加密,并返回  
 * DL_RED_PACKET 字符串是跟后台协定的  
 */  
function getRSA(o, describe) {  
    var encrypt = new JSEncrypt();  
    encrypt.setPublicKey(USERINFO.DL_PUBLIC_KEY); //设置公有key  
    var keys = Object.keys(o).sort();  
    if(arguments.length <= 0) return false;  
    var str = '';  
    for(var i = 0; i < keys.length; i++) {  
        if(keys[i] != 'sign') {  
            str += o[keys[i]];  
        }  
    }  
    var sign = '';  
    str = encodeURI(str + 'DL_RED_PACKET');  
    for(var i = 0; i <= parseInt(str.length / 117); i++) {  
        sign += encrypt.encrypt(str.substr(i * 117, 117))  
    }  
    return sign;  
}
收起阅读 »

新浪微博分享链接

微博分享

新浪微博的分享链接不是单独出来的,并与图片产生冲突。
所以不要将分享的链接写到msg.href中,而是拼接在content中,如果链接经过新浪官方验证,则会显示概览信息(此信息与图片冲突)。
发此文还有个原因是告诉大家,新浪分享本来就是这样的,这个不是一个折衷的方案,好使,不用找别的了。
错怪官方这么久没修复这个东西 =。=

ps.回调地址没有的可以用默认 https://api.weibo.com/oauth2/default.html

站内相关问题参考:
http://ask.dcloud.net.cn/article/707
http://ask.dcloud.net.cn/question/8353 (此文基本囊括遇到问题)

继续阅读 »

新浪微博的分享链接不是单独出来的,并与图片产生冲突。
所以不要将分享的链接写到msg.href中,而是拼接在content中,如果链接经过新浪官方验证,则会显示概览信息(此信息与图片冲突)。
发此文还有个原因是告诉大家,新浪分享本来就是这样的,这个不是一个折衷的方案,好使,不用找别的了。
错怪官方这么久没修复这个东西 =。=

ps.回调地址没有的可以用默认 https://api.weibo.com/oauth2/default.html

站内相关问题参考:
http://ask.dcloud.net.cn/article/707
http://ask.dcloud.net.cn/question/8353 (此文基本囊括遇到问题)

收起阅读 »

查看流应用统计数据

统计 流应用

开发者发布流应用后,可以登录DCloud开发者中心查看流应用的统计数据。

开发者登录后,会在首页展现所有已创建的应用列表,包括5+App、流应用、快应用等;

从列表中点击某个应用,可以查看该应用不同版本的的日活趋势、新增来源等统计数据。

应用趋势

开发者可以从多个维度查看具体应用的趋势数据,比如当日新增下载、新增激活、当日日活、启动次数等维度。

应用来源

流应用可以从多个场景触发,比如浏览器、应用市场、扫码等,开发者可以查看流应用的启动来源,分析各渠道推广效果。

继续阅读 »

开发者发布流应用后,可以登录DCloud开发者中心查看流应用的统计数据。

开发者登录后,会在首页展现所有已创建的应用列表,包括5+App、流应用、快应用等;

从列表中点击某个应用,可以查看该应用不同版本的的日活趋势、新增来源等统计数据。

应用趋势

开发者可以从多个维度查看具体应用的趋势数据,比如当日新增下载、新增激活、当日日活、启动次数等维度。

应用来源

流应用可以从多个场景触发,比如浏览器、应用市场、扫码等,开发者可以查看流应用的启动来源,分析各渠道推广效果。

收起阅读 »

ios蓝牙调戏一代小米手环

蓝牙 iOS

先上效果图

手环是小米一代光感版的,二代手环没有试过,地址有改变,应该调戏不了。
为什么说是调戏呢?
因为这一代小米手环有一些设置没有验证措施,随便一个手机都能读取手环的一些简单数据。
比如电量,步数,控制震动,其中很重要的控制震动竟然都不需要验证,希望二代手环有修复这个问题。
其他功能小米有限制,没有权限读取,要向小米申请,我就不折腾了。

我写得比较急,代码太难看了,就放两个截图吧。


Xcode上写的JS,这个乱真不怪我,Xcode会自动把js给缩进,开始时候还耐心的改一下,后面的又开始夸张的缩进,我就索性不管了。

插件引用了BabyBluetooth,放一下这个项目地址:https://github.com/coolnameismy/BabyBluetooth
BabyBluetooth还真好用。不用像原生CoreBluetooth那样凌乱了。

其实插件完全的按照官方文档还是能做出来的,虽然是门槛高一点,但是代码可控,用起来舒心。

继续阅读 »

先上效果图

手环是小米一代光感版的,二代手环没有试过,地址有改变,应该调戏不了。
为什么说是调戏呢?
因为这一代小米手环有一些设置没有验证措施,随便一个手机都能读取手环的一些简单数据。
比如电量,步数,控制震动,其中很重要的控制震动竟然都不需要验证,希望二代手环有修复这个问题。
其他功能小米有限制,没有权限读取,要向小米申请,我就不折腾了。

我写得比较急,代码太难看了,就放两个截图吧。


Xcode上写的JS,这个乱真不怪我,Xcode会自动把js给缩进,开始时候还耐心的改一下,后面的又开始夸张的缩进,我就索性不管了。

插件引用了BabyBluetooth,放一下这个项目地址:https://github.com/coolnameismy/BabyBluetooth
BabyBluetooth还真好用。不用像原生CoreBluetooth那样凌乱了。

其实插件完全的按照官方文档还是能做出来的,虽然是门槛高一点,但是代码可控,用起来舒心。

收起阅读 »