PhoneGap 教程:一个跨平台的 Todo App

PhoneGap 是一个允许开发者使用熟悉的网页开发技术,例如HTML,CSS 和 JavaScript 去开发跨平台应用的手机开发框架。

也就是说你可以使用 PhoneGap 架构开发一款应用,不需要重写额外一行代码就可以将它部署到多个移动应用平台。

在这个教程中,你将学习使用 PhoneGap 去创建一款简单的 to-do 应用。在这个过程中你会学习到很多 PhoneGap 的知识,例如安装 PhoneGap,编写 Javascript 代码,使用本地存储等等~

这个教程假设你已经有基本的 HTML ,CSS 和 Javascript 基础。如果你是对这方面是一无所知的话,你同样可以跟随教程一起学习,但是你会错过很多相关的背景知识,所以还是建议你去阅读一下这方面的书籍先。

开始

和其他任何新建的项目一样,去构想一下你要创建的app的外观总是不错的。

下面是你将要构建的app的外观:

简单地,这只是让你了解到你接下来所有做的事而已。屏幕的上方是一个app Logo,Logo 下面有两个按钮;一个是增加新任务,一个是移除已完成的项目。当用户新增一条待做项到待做列表的时候,表格就会创建一个包含四个元素的行。

首先,你有一个 checkbox 表示待做项的状态,接下来是一个填写待做内容的输入框,最后还有两个按钮,一个是以弹出框的形式展示待做内容,另一个是删除待做项。

该 app 使用本地存储 API 保存待做项。

还有一点,谢谢这位大哥 Vicki Wenderlich ,是他帮我设计的图片,所以app就长这样了。

是时候看一下app有啥功能了:

  • 增加待做项:当按下 Add To-Do 按钮的时候,用户可以立刻输入待做的内容到待做列表项中。
  • 标记待做项为已完成状态:用户可以点击待做项左边的checkbox标记待做项已完成。
  • 移除已完成的待做项:点击 Remove Completed Tasks 按钮移除所有已完成的任务。
  • 查看待做项:当点击View按钮的时候可以查看完整的待做项内容。
  • 删除待做项:点击Delete按钮会删除相应的待做项。

总的来说,这是一个相当简单的app,使用phoneGap开发这个应用的目的是为了举例说明不使用原生API也能开发出一个完整的app,并且能够在多平台上使用。

安装 PhoneGap

Note:如果你已经安装PhoneGap可以直接跳过这一部分。由于作者写这篇文章的时候使用的是PhoneGap 2.3.0的,到现在已经更新到2.9.1了,就直接使用新的API了。

PhoneGap 的官网:Here

Docs: Install PhoneGap The Comman-Line Interface 或者看下面:

在安装PhoneGap之前,先确保你已经安装了 NodeJS,打开你的终端,输入以下命令:

sudo npm install -g cordova

去到你想要保存该项目的文件夹,在终端输入:

cordova create Zombie com.aaron.zombie ZombieApocalypseToDoList

可以看到创建了如下文件夹:

但是platforms还是空的,现在我们来为它添加ios平台代码,在终端输入:

cordova platform add ios

安装完成就看在Zombie/platforms/ 目录下看到 ios这个目录了

添加其他平台支持看The Command-Line Interface 和Platform
Guides

在XCode 中打开 .xcodeproj 文件,跑一下就可以看到效果了。

构建你的应用程序

上面看到的App第一次打开的页面是 ios/www/ 下的index.html界面 ,所以这一部分就是修改 index.html 的代码让它变成我们想要的样子。

用下面的代码替换 index.html 的代码:

<!DOCTYPE html>
<html>
    <head>
        <title>Zombie Apocalypse To-Do List</title>
        <link rel="stylesheet" type="text/css" href="css/index.css"/>
        <script type="text/javascript" language="JavaScript">

        </script>
    </head>
    <body>

    </body>
</html>

在 index.html 界面的body标签中增加以下代码:

<input type="button" value="Add To-Do"/>
<input type="button" value="Remove Completed Tasks"/>
<br/><br/>
<table id="dataTable" width="100%" border="1">

</table>

编译运行app,它看起来会是这样:

几行代码就搞定2个按钮,现在你需要为这些按钮添加功能。

用Javascript编写:总预览

为了支持应用的功能,你需要添加一些javascript函数。

在你实现这些函数之前,我们先来总的预览一下需要为你的app创建哪些函数。

createNewToDo()

弹出框提示用户输入待做项,一旦用户点击弹出框上的OK按钮,一个新的待做项就被添加到列表中。

addTableRow(todoDictionary, appIsLoading)

增加一行到待做列表中。该函数有2个形参:一个字典包含待做项内容和一个表示app是否在运行的状态值

checkBoxClicked()

checkbox改变的时候被调用

viewSelectedRow(todoTextField)

以弹出框的形式展示待做项内容。

deleteSelectedRow(deleteButton)

删除选择待做项的行。

removeCompletedTasks()

循环整个列表,删除那些被标记为以完成状态的待做项。

saveToDoList()

使用本地存储API保存待做项列表

loadToDoList()

在app第一次启动的时候使用本地存储API加载待做项列表。

deleteAllRows()

删除所有行。

这就是所有需要用的的函数,在接下来的教程中,如果你有关于该函数的任何疑问,可以返回来在看看。

Javascript:实现

Note:下面的代码段,除非特别指明,否则它们都一律放在index.htmlscript标签中。

增加以下代码:

// create a new to-do
function createNewToDo()
{
    var todoDictionary = {};

    // prompt the user to enter to-do
    var todo = prompt("To-Do","");
    if (todo != null)
    {
        if (todo == "")
        {
            alert("To-Do can't be empty!");
        }
        else
        {
            // append the new to-do with the table
            todoDictionary = { check : 0 , text : todo};
            addTableRow(todoDictionary, false);
        }
    }

}

createNewToDo() 非常的简单易懂,它只是简单的弹出一个输入框让用户输入待做项。如果待做项内容是空的话就提醒用户待做内容不能为空,否则就调用 addTableRow() 函数。

增加以下代码:

// add a row to the table
var rowID = 0;
function addTableRow(todoDictionary, appIsLoading)
{
    rowID +=1;
    var table = document.getElementById("dataTable");
    var rowCount = table.rows.length;
    var row = table.insertRow(rowCount);

    // create the checkbox
    var cell1 = row.insertCell(0);
    var element1 = document.createElement("input");
    element1.type = "checkbox";
    element1.name = "chkbox[]";
    element1.checked = todoDictionary["check"];
    element1.setAttribute("onclick", "checkboxClicked()");
    cell1.appendChild(element1);

    // create the textbox
    var cell2 = row.insertCell(1);
    var element2 = document.createElement("input");
    element2.type = "text";
    element2.name = "txtbox[]";
    element2.size = 16;
    element2.id = "text" + rowID;
    element2.value = todoDictionary["text"];
    element2.setAttribute("onchange", "saveToDoList()");
    cell2.appendChild(element2);

    // create the view button
    var cell3 = row.insertCell(2);
    var element3 = document.createElement("input");
    element3.type = "button";
    element3.id = rowID;
    element3.value = "View";
    element3.setAttribute("onclick", "viewSelectedRow(document.getElementById('text' + this.id))");
    cell3.appendChild(element3);

    // create the delete button
    var cell4 = row.insertCell(3);
    var element4 = document.createElement("input");
    element4.type = "button";
    element4.value = "Delete";
    element4.setAttribute("onclick", "deleteSelectedRow(this)");
    cell4.appendChild(element4);

    // update the UI and save the to-do list
    checkboxClicked();
    saveToDoList();

    if (!appIsLoading) alert("Task Added Successfully.");
}

当 addTableRow() 方法被调用的时候,一个包含4个cell的新行就会被插入到待做列表中。最后调用 checkboxClicked() 和 saveToDoList() 来更新UI和保存待做列表项数据。

增加如下代码:

// add the strike-through styling to completed tasks
function checkboxClicked()
{
    var table = document.getElementById("dataTable");
    var rowCount = table.rows.length;

    // loop through all rows of the table
    for(var i = 0; i < rowCount; i++)
    {
        var row = table.rows[i];
        var chkbox = row.cells[0].childNodes[0];
        var textbox = row.cells[1].childNodes[0];

        // if the checkbox is checked, add the strike-through styling
        if(null != chkbox && true == chkbox.checked)
        {
            if(null != textbox)
            {
                textbox.style.setProperty("text-decoration", "line-through");
            }
        }

        // if the checkbox isn't checked, remove the strike-through styling
        else
        {
            textbox.style.setProperty("text-decoration", "none");
        }

    }

    // save the to-do list
    saveToDoList();
}

标记待做项的完成情况。


增加如下代码:

// view the content of the selected row
function viewSelectedRow(todoTextField)
{
    alert(todoTextField.value);
}

简单的展示待做项内容。

增加如下代码:

// delete the selected row
function deleteSelectedRow(deleteButton)
{
    var p = deleteButton.parentNode.parentNode;
    p.parentNode.removeChild(p);
    saveToDoList();
}

删除选中行。

增加如下代码:

// remove completed tasks
function removeCompletedTasks()
{
    var table = document.getElementById("dataTable");
    var rowCount = table.rows.length;

    // loop through all rows of the table
    for(var i = 0; i < rowCount; i++)
    {
        // if the checkbox is checked, delete the row
        var row = table.rows[i];
        var chkbox = row.cells[0].childNodes[0];
        if(null != chkbox && true == chkbox.checked)
        {
            table.deleteRow(i);
            rowCount--;
            i--;
        }
    }

    // save the to-do list
    saveToDoList();

    alert("Completed Tasks Were Removed Successfully.");
}

遍历待做项列表,检查checkbox状态是否为完成,如果是这从待做列表项中删除,然后更新并保存待做列表,提示用户已经完成。

增加如下代码:

// save the to-do list
function saveToDoList()
{
    var todoArray = {};
    var checkBoxState = 0;
    var textValue = "";

    var table = document.getElementById("dataTable");
    var rowCount = table.rows.length;

    if (rowCount != 0)
    {
        // loop through all rows of the table
        for(var i=0; i<rowCount; i++)
        {
            var row = table.rows[i];

            // determine the state of the checkbox
            var chkbox = row.cells[0].childNodes[0];
            if(null != chkbox && true == chkbox.checked)
            {
                checkBoxState = 1;
            }
            else
            {
                checkBoxState= 0;
            }

            // retrieve the content of the to-do
            var textbox = row.cells[1].childNodes[0];
            textValue = textbox.value;

            // populate the array
            todoArray["row" + i] =
            {
                check : checkBoxState,
                text : textValue
            };
        }
    }
    else
    {
        todoArray = null;
    }

    // use the local storage API to persist the data as JSON
    window.localStorage.setItem("todoList", JSON.stringify(todoArray));
}

保存待做列表项数据到本地。

既然已经将数据保存到本地了,你就得在app再次启动的时候将它加载回来,是吧?

那么,增加如下代码:

// load the to-do list
function loadToDoList()
{
    // use the local storage API load the JSON formatted to-do list, and decode it
    var theList = JSON.parse(window.localStorage.getItem("todoList"));

    if (null == theList || theList == "null")
    {
        deleteAllRows();
    }
    else
    {
        var count = 0;
        for (var obj in theList)
        {
            count++;
        }

        // remove any existing rows from the table
        deleteAllRows();

        // loop through the to-dos
        for(var i = 0; i < count; i++)
        {
            // adding a row to the table for each one
            addTableRow(theList["row" + i], true);
        }
    }
}

增加如下代码:

// delete all the rows
function deleteAllRows()
{
    var table = document.getElementById("dataTable");
    var rowCount = table.rows.length;

    // loop through all rows of the table
    for(var i = 0; i < rowCount; i++)
    {
        // delete the row
        table.deleteRow(i);
        rowCount--;
        i--;
    }

    // save the to-do list
    saveToDoList();
}

删除所有行。

将所有函数归到一起

写了那么多,终于写完所有接口的实现了,现在来看一下它跑起来是什么样子。

调用上面的方法很简单,只需要为按钮增加一个onClick 事件就行了。

在 index.html 的 body 标签中增加如下代码:

<body onload="loadToDoList()">
    <input type="button" value="Add To-Do" onclick="createNewToDo()"/>
    <input type="button" value="Remove Completed Tasks()" onclick="removeCompletedTasks()"/>
    <br/><br/>
    <table id="dataTable" width="100%" border="1">

    </table>
</body>

上面的代码中,当app第一次加载的时候就会被调用。createNewToDo()函数和 removeCompletedTasks() 函数在点击相应的按钮的时候就会被调用。

编译并运行一下,就可以看到如下效果了:

javascript 的一个弊端之一就是它一个解释型语言,不想 Object-C等其他编译类型的语言,在代码不小心写错的时候不会即时的报错,只有在运行时执行到某一句错误的代码时才Crash掉,所以在调试的时候也是挺麻烦的。

tips:当运行时出错的时候,你可以用你熟悉的浏览器所提供的开发者工具进行调试。

一切看起来都还不错,只是界面有点单调。好吧,我们再为它加一些其他的内容。

美化你的APP

该有的功能都有了,是时候美化一下app了。

这里下载一些必要的图片资源。(额~,不得不说作者有点重口,僵尸主题),将下载完的图片复制到工程的 img目录下。

在 index.html 的 body 标签中增加如下行:

<img src="img/header.png" width="100%" />

既然你是用HTML技术实现你的app,就避免不了使用CSS去设计app的样式和布局。

每一个你想要展示的样式都需要一个 class 元素,下面你将开始用 CSS 布局你app中的button样式。

<button type="button" class="addToDo" onclick="createNewToDo()"><img src="img/button_addtodo.png" /></button>
<button type="button" class="removeTasks" onclick="removeCompletedTasks()"><img src="img/button_removetasks.png" /></button>

你现在已经为button添加了一个class属性,接下来你就可以使用CSS布局button的样式了。

同样,你需要为app中的checkboxes,textboxes和其他button添加 class 属性,以便使用CSS样式。

更新 index.html 的代码,增加如下代码:

...
element1.setAttribute("onclick","checkboxClicked()");
element1.className = "checkbox"; // ADD ME - Add the class name 'checkbox' to element1
cell1.appendChild(element1);
...
element2.setAttribute("onchange", "saveToDoList()");
element2.className = "textbox"; // ADD ME - Add the class name 'textbox' to element2
cell2.appendChild(element2);
...
element3.setAttribute("onclick", "viewSelectedRow(document.getElementById('text' + this.id))");
element3.className = "viewButton"; // ADD ME - Add the class name 'viewButton' to element3
cell3.appendChild(element3);
...
element4.setAttribute("onclick", "deleteSelectedRow(this)");
element4.className = "deleteButton"; // ADD ME - Add the class name 'deleteButton' to element4
cell4.appendChild(element4);

现在是时候编写HTML中所引用到的CSS样式代码了。

打开 index.css (在Zombie/www/css/目录下),找到如下代码:

background-color:#E4E4E4;
background-image:linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
background-image:-webkit-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
background-image:-ms-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
background-image:-webkit-gradient(
    linear,
    left top,
    left bottom,
    color-stop(0, #A7A7A7),
    color-stop(0.51, #E4E4E4)
);
background-attachment:fixed;

这段代码提供了一个梯度效果的背景,但在该app中我们不会使用它,等下我们会使用更合适的背景替换该背景效果。

用下面的代码替换上面的代码段:

background-image: url('../img/bg_pattern.png');

恩,背景现在已经换成bg_pattern.png这张图片。

滚动到 index.css 最后,增加如下代码:

.addToDo {
background-color: Transparent;
border-color: Transparent;
float: left;
margin-left: 0;
position: absolute;
left: 0px
}

.removeTasks {
background-color: Transparent;
border-color: Transparent;
float: right;
margin-right: 0;
position: absolute;
right: 0px;
}

.checkbox {
background-color: Transparent;
background-image: url('../img/check_box.png');
width: 34px;
height: 32px;
}

.textbox {
background-color: grey;
}

.viewButton {
background-color: Transparent;
background-image: url('../img/button_view.png');
width: 64px;
height: 32px;
}

.deleteButton {
background-color: Transparent;
background-image: url('../img/button_delete.png');
width: 64px;
height: 32px;
}

代码中的每一个类样式—— .deleteButton.viewButton等等定义了UI元素的背景颜色,背景图片,宽,高等等~

再运行一下,就可以看到下面的效果了。

哇,是不是看起来很不一样了。至此,app就算完成了。

使用 PhoneGap 的一个好处就是你可以不用修改一行代码就可以发布到任意多个平台,下面简单看一下如何做吧:

发布你的 App

在上传到 Adobe Build 的时候你首先得压缩一下你的项目。

压缩完 Zombie 项目之后,打开 https://build.phonegap.com/ 这个网站,点击 Get started! 开始发布你的app 流程。

这里面有一个 Paid plan,当你有更多的私人app要发布的时候你可以调查一下该支付计划,但 PhoneGap 这个教程的目的并不是这个,所有还是选择 completely free 吧

使用 Adobe ID 或者 Github 账号登陆

登陆完成之后 点击 Upload a .zip file ,选择打包好的 Zombie.zip 文件,开始上传。上传完成后,点击 Ready to build 按钮,如下:

当 build 完成之后,你就可以看到PhonGap支持的多个移动平台的编译状态。如下,其他平台的都是蓝色,只有 IOS 和 黑莓的显示为红色,说明这两个平台的编译出了问题。

点击红色的 ios ,然后再点击下拉框,你会看到要求你上传 certificate 和 provisioning profile 这两个文件。

作为一个ios开发者,证书肯定是有的,从 keychain 导出来就可以了;如果你还没有证书的话,可以看一下苹果官方的教程:App
Store Submission Turorial

使用 Spotlight 查找 KeyChain Access. 如果你之前已经安装过开发者证书,你就能在这里找到它,现在我们来导出它。

选择 My Certificates 分类,右击 iPhone Distribution... ,在弹出框中选择 Export ”iPhone Distribution..."。如下图:

导出过程中确认你使用的是 Personal Information Export(.p12)格式导出,即导出的格式后缀是 .p12 的。为你导出的证书填入一个密码,下面会用到。最后点击 OK 就可以将证书成功导出了。

现在你已经有一个证书了,你还需要再创建一个配置文件。打开苹果开发者中心 developer.apple.com 并登陆你的开发者账号。

在开是创建配置文件之前,你需要为你的 Zombie App 创建一个 App ID。

在左边的选项中选择 APP IDs,在下一页中,点击 New App ID。填写表格的一些必要字段,确认你在 Bundle Identifier 字段中输入 com.raywenderlich.zombie(这里的内容你跟你创建项目是填在Bundle
Identifier 中的一样的。)如下:

最后,点击 Submit.

当你完成App ID 的创建的时候,选择左边的 options 选项的 Provsioning ,在下一页中,选择 Distribution 选项卡,点击 New Profile ,填写一些必要的信息,选择你刚刚创建的App
ID,选择你要安装的设备,最后,点击 Submit,配置文件就创建好了。

完成以上操作后,下载创建好的配置文件。将配置文件和证书都导入进入,如下:

点击黄色的锁头按钮,输入你刚刚创建的证书的密码,如下:

最后,点击 Submit key。稍等一会儿你就可以看到它已经帮你创建好了一个可以下载的 .ipa 文件了。

完整地项目代码放在这里,稍微修改了一下,有需要的来这里拿吧,source code 这是没有修改过的。

参考链接:

the PhoneGap API reference

另外可以看一下使用 PhoneGap 编写的一些优秀软件:check out the full list

原文链接:http://www.raywenderlich.com/30734/phonegap-tutorial-a-cross-platform-zombie-app

时间: 2024-11-08 02:32:16

PhoneGap 教程:一个跨平台的 Todo App的相关文章

小白学phoneGap《构建跨平台APP:phoneGap移动应用实战》连载五(使用PhoneGap获取设备信息)

除了能够将HTML页面打包成可以直接安装运行的APP外,PhoneGap的一个最大优势在于可以通过JavaScript调用设备来访问设备上的硬件信息,从而实现一些原本只有依靠原生SDK才能够达到的目的.范例5-1就展示了一个利用API来获取设备信息的例子. [范例5-1 利用PhoneGap获取设备信息] <!DOCTYPE html> <html> <meta http-equiv="Content-Type" content="text/ht

使用PhoneGap搭建一个山寨京东APP

为什么要写一个App 首先解释下写出来的这个App,其实无任何功能,只是用HTML和CSS模仿JD移动端界面写的一个适配移动端的Web界面.本篇主要内容是介绍如何使用PhoneGap把开发出来的mobile web app快速打包成Native App.最近还在学习HTML&CSS以及Javascript,偶然想想学这些有什么用,一方面可以做Web系统的前端开发,另一方面也可以做移动端的Web App.刚好最近了解到PhoneGap,研究了一下它的框架平台,花了两个晚上终于把一个web系统变成了

Swift 编写的一个 ToDo App

以下所有代码都是使用Xcode Version 6.0.1 (6A317)编写的. 由于团队开发的时候使用stroyboard在合并的时候有诸多不便,所有还是使用.xib文件编写这个ToDo App. 想要实现的功能是:TableView 上可以增加待做选项,并按照时间先后排序,可以实现删除,到点通知功能. 想要实现的效果如下:        步骤: 1.新建一个基于Singal View Application 的工程,然后删掉storyboard,在新建两个新文件 Main.xib 和 Ma

为PhoneGap写一个android插件

为PhoneGap写一个android插件,要怎么做? 其实这句话应该反过来说,为android写一个PhoneGap插件,要怎么做? 这里以最简单的Hello World!为例,做个说明: 1.第一步,要先建立一个支持PhoneGap(Cordova)的android工程 因为这个插件本质上是安卓插件,用于PhoneGap,因此,要二者支持才行,所以我们要建立一个支持PhoneGap(Cordova)的android工程,插件在这个工程里面编写. 扫盲:PhoneGap现在已经出售给了Apac

移动应用跨平台开发:《用PhoneGap来开发跨平台手机应用》

移动应用跨平台开发:<用PhoneGap来开发跨平台手机应用> 随着HTML5, CSS3, Javascript的发展,以及浏览器对这些特性的支持,使得手机跨平台成为一种趋势,跨平台意味着:开发一次,到处运行.基于(HTML5, CSS3, Javascript)的前端开发技术,可以通过PhoneGap(http://phonegap.com/)来生成对应设备的应用,如Android的APK, iOS设备的ipa等.相比原生态的应用来讲,PhoneGap开发出来的应用成本更低,甚至不需要会J

十分钟使用ionic Framework开发一个跨平台移动应用

Ionic是一个前端的框架,帮助开发者使用HTML5, CSS3和JavaScript做出原生应用.ionic的理念类似前端开发的BootStrap,目标是封装HTML5移动跨平台开发的最佳实践,就像Twitter Bootstrap在前端开发中做的一样.Ionic框架目前发展很迅速,我们从2014年3月开始使用,当时是1.0.0beta2,现在已经更新到1.0.0beta10,大概每2个星期会出一个beta版本,并且都包含实质性更新.Ionic框架很先进,js部分是基于AngularJS框架,

开源一个跨平台运行的服务插件 - TaskCore.MainForm

本次将要很大家分享的是一个跨平台运行的服务插件 - TaskCore.MainForm,此框架是使用.netcore来写的,现在netcore已经支持很多系统平台运行了,所以将以前的Task.MainForm改良成跨平台的服务共大家使用和相互交流:本来这篇应该分享的是nginx+iis+redis+Task.MainForm构建分布式架构后续文章,但使用.netcore来定义一个服务插件和跨平台测试经过让我既兴奋又头痛,不说了下次再分享分布式后续文章吧:那么开始今天的分享内容,希望各位多多支持:

开源一个自己写的APP:装哔指南-记车标

想想我做安卓开发到现在也快两年了,所在的公司基本都是在做企业内部应用,自己每次做的一些小应用,都是做到一半或者快完成的时候放着积灰了.感觉很没有成就感啊!这两天心血来潮写了一个小应用:装哔指南-记车标 ,(花了两天,其中一天在搜集车标数据弄数据库 0.0 )顺便发出来给一些新手们学习学习(我也新手=.=   大神请绕道.) 下面简单介绍一下应用里面用到的知识点: 1. android SQLite 的简单使用. 2. listview和gridview 配合 BaseAdapter的使用方法.

想实现一个类似于收趣APP的功能,求助

近日想做一个类似于收趣APP软件的一个功能,将头条.微信等其他App的文章能够分享到自己的平台软件中. 分享的方式有三种: 1.通过微信好友的方式,将文章分享给收趣. 2.复制文章链接,然后打开收趣App后,软件自动识别粘贴板然后提示是否收藏. 3.通过系统分享.(暂不考虑) 基于第一种方式思考如下: 1.收趣是针对每一个注册用户生成一个微信客服号,然后在收趣上分享一个文章给该客服号(这个客服号跟收趣客户并不是一对一的)完成绑定.分享的这个文章应该是暗含收趣的账号,这样就完成了微信号与收趣号的绑