Authored by gaoqiang xu

first commit

Showing 32 changed files with 4883 additions and 0 deletions

Too many changes to show.

To preserve performance only 32 of 32+ files are displayed.

*.xccheckout
... ...
#YHExplorer
... ...
No preview for this file type
<!DOCTYPE html><html><head><meta charset="utf-8"><style>body {
width: 45em;
border: 1px solid #ddd;
outline: 1300px solid #fff;
margin: 16px auto;
}
body .markdown-body
{
padding: 30px;
}
@font-face {
font-family: octicons-anchor;
src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAYcAA0AAAAACjQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABMAAAABwAAAAca8vGTk9TLzIAAAFMAAAARAAAAFZG1VHVY21hcAAAAZAAAAA+AAABQgAP9AdjdnQgAAAB0AAAAAQAAAAEACICiGdhc3AAAAHUAAAACAAAAAj//wADZ2x5ZgAAAdwAAADRAAABEKyikaNoZWFkAAACsAAAAC0AAAA2AtXoA2hoZWEAAALgAAAAHAAAACQHngNFaG10eAAAAvwAAAAQAAAAEAwAACJsb2NhAAADDAAAAAoAAAAKALIAVG1heHAAAAMYAAAAHwAAACABEAB2bmFtZQAAAzgAAALBAAAFu3I9x/Nwb3N0AAAF/AAAAB0AAAAvaoFvbwAAAAEAAAAAzBdyYwAAAADP2IQvAAAAAM/bz7t4nGNgZGFgnMDAysDB1Ml0hoGBoR9CM75mMGLkYGBgYmBlZsAKAtJcUxgcPsR8iGF2+O/AEMPsznAYKMwIkgMA5REMOXicY2BgYGaAYBkGRgYQsAHyGMF8FgYFIM0ChED+h5j//yEk/3KoSgZGNgYYk4GRCUgwMaACRoZhDwCs7QgGAAAAIgKIAAAAAf//AAJ4nHWMMQrCQBBF/0zWrCCIKUQsTDCL2EXMohYGSSmorScInsRGL2DOYJe0Ntp7BK+gJ1BxF1stZvjz/v8DRghQzEc4kIgKwiAppcA9LtzKLSkdNhKFY3HF4lK69ExKslx7Xa+vPRVS43G98vG1DnkDMIBUgFN0MDXflU8tbaZOUkXUH0+U27RoRpOIyCKjbMCVejwypzJJG4jIwb43rfl6wbwanocrJm9XFYfskuVC5K/TPyczNU7b84CXcbxks1Un6H6tLH9vf2LRnn8Ax7A5WQAAAHicY2BkYGAA4teL1+yI57f5ysDNwgAC529f0kOmWRiYVgEpDgYmEA8AUzEKsQAAAHicY2BkYGB2+O/AEMPCAAJAkpEBFbAAADgKAe0EAAAiAAAAAAQAAAAEAAAAAAAAKgAqACoAiAAAeJxjYGRgYGBhsGFgYgABEMkFhAwM/xn0QAIAD6YBhwB4nI1Ty07cMBS9QwKlQapQW3VXySvEqDCZGbGaHULiIQ1FKgjWMxknMfLEke2A+IJu+wntrt/QbVf9gG75jK577Lg8K1qQPCfnnnt8fX1NRC/pmjrk/zprC+8D7tBy9DHgBXoWfQ44Av8t4Bj4Z8CLtBL9CniJluPXASf0Lm4CXqFX8Q84dOLnMB17N4c7tBo1AS/Qi+hTwBH4rwHHwN8DXqQ30XXAS7QaLwSc0Gn8NuAVWou/gFmnjLrEaEh9GmDdDGgL3B4JsrRPDU2hTOiMSuJUIdKQQayiAth69r6akSSFqIJuA19TrzCIaY8sIoxyrNIrL//pw7A2iMygkX5vDj+G+kuoLdX4GlGK/8Lnlz6/h9MpmoO9rafrz7ILXEHHaAx95s9lsI7AHNMBWEZHULnfAXwG9/ZqdzLI08iuwRloXE8kfhXYAvE23+23DU3t626rbs8/8adv+9DWknsHp3E17oCf+Z48rvEQNZ78paYM38qfk3v/u3l3u3GXN2Dmvmvpf1Srwk3pB/VSsp512bA/GG5i2WJ7wu430yQ5K3nFGiOqgtmSB5pJVSizwaacmUZzZhXLlZTq8qGGFY2YcSkqbth6aW1tRmlaCFs2016m5qn36SbJrqosG4uMV4aP2PHBmB3tjtmgN2izkGQyLWprekbIntJFing32a5rKWCN/SdSoga45EJykyQ7asZvHQ8PTm6cslIpwyeyjbVltNikc2HTR7YKh9LBl9DADC0U/jLcBZDKrMhUBfQBvXRzLtFtjU9eNHKin0x5InTqb8lNpfKv1s1xHzTXRqgKzek/mb7nB8RZTCDhGEX3kK/8Q75AmUM/eLkfA+0Hi908Kx4eNsMgudg5GLdRD7a84npi+YxNr5i5KIbW5izXas7cHXIMAau1OueZhfj+cOcP3P8MNIWLyYOBuxL6DRylJ4cAAAB4nGNgYoAALjDJyIAOWMCiTIxMLDmZedkABtIBygAAAA==) format('woff');
}
.markdown-body {
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
color: #333;
overflow: hidden;
font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;
font-size: 16px;
line-height: 1.6;
word-wrap: break-word;
}
.markdown-body a {
background: transparent;
}
.markdown-body a:active,
.markdown-body a:hover {
outline: 0;
}
.markdown-body strong {
font-weight: bold;
}
.markdown-body h1 {
font-size: 2em;
margin: 0.67em 0;
}
.markdown-body img {
border: 0;
}
.markdown-body hr {
-moz-box-sizing: content-box;
box-sizing: content-box;
height: 0;
}
.markdown-body pre {
overflow: auto;
}
.markdown-body code,
.markdown-body kbd,
.markdown-body pre {
font-family: monospace, monospace;
font-size: 1em;
}
.markdown-body input {
color: inherit;
font: inherit;
margin: 0;
}
.markdown-body html input[disabled] {
cursor: default;
}
.markdown-body input {
line-height: normal;
}
.markdown-body input[type="checkbox"] {
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 0;
}
.markdown-body table {
border-collapse: collapse;
border-spacing: 0;
}
.markdown-body td,
.markdown-body th {
padding: 0;
}
.markdown-body * {
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.markdown-body input {
font: 13px/1.4 Helvetica, arial, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol";
}
.markdown-body a {
color: #4183c4;
text-decoration: none;
}
.markdown-body a:hover,
.markdown-body a:focus,
.markdown-body a:active {
text-decoration: underline;
}
.markdown-body hr {
height: 0;
margin: 15px 0;
overflow: hidden;
background: transparent;
border: 0;
border-bottom: 1px solid #ddd;
}
.markdown-body hr:before {
display: table;
content: "";
}
.markdown-body hr:after {
display: table;
clear: both;
content: "";
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
margin-top: 15px;
margin-bottom: 15px;
line-height: 1.1;
}
.markdown-body h1 {
font-size: 30px;
}
.markdown-body h2 {
font-size: 21px;
}
.markdown-body h3 {
font-size: 16px;
}
.markdown-body h4 {
font-size: 14px;
}
.markdown-body h5 {
font-size: 12px;
}
.markdown-body h6 {
font-size: 11px;
}
.markdown-body blockquote {
margin: 0;
}
.markdown-body ul,
.markdown-body ol {
padding: 0;
margin-top: 0;
margin-bottom: 0;
}
.markdown-body ol ol,
.markdown-body ul ol {
list-style-type: lower-roman;
}
.markdown-body ul ul ol,
.markdown-body ul ol ol,
.markdown-body ol ul ol,
.markdown-body ol ol ol {
list-style-type: lower-alpha;
}
.markdown-body dd {
margin-left: 0;
}
.markdown-body code {
font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace;
}
.markdown-body pre {
margin-top: 0;
margin-bottom: 0;
font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace;
}
.markdown-body .octicon {
font: normal normal 16px octicons-anchor;
line-height: 1;
display: inline-block;
text-decoration: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.markdown-body .octicon-link:before {
content: '\f05c';
}
.markdown-body>*:first-child {
margin-top: 0 !important;
}
.markdown-body>*:last-child {
margin-bottom: 0 !important;
}
.markdown-body .anchor {
position: absolute;
top: 0;
bottom: 0;
left: 0;
display: block;
padding-right: 6px;
padding-left: 30px;
margin-left: -30px;
}
.markdown-body .anchor:focus {
outline: none;
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
position: relative;
margin-top: 1em;
margin-bottom: 16px;
font-weight: bold;
line-height: 1.4;
}
.markdown-body h1 .octicon-link,
.markdown-body h2 .octicon-link,
.markdown-body h3 .octicon-link,
.markdown-body h4 .octicon-link,
.markdown-body h5 .octicon-link,
.markdown-body h6 .octicon-link {
display: none;
color: #000;
vertical-align: middle;
}
.markdown-body h1:hover .anchor,
.markdown-body h2:hover .anchor,
.markdown-body h3:hover .anchor,
.markdown-body h4:hover .anchor,
.markdown-body h5:hover .anchor,
.markdown-body h6:hover .anchor {
padding-left: 8px;
margin-left: -30px;
line-height: 1;
text-decoration: none;
}
.markdown-body h1:hover .anchor .octicon-link,
.markdown-body h2:hover .anchor .octicon-link,
.markdown-body h3:hover .anchor .octicon-link,
.markdown-body h4:hover .anchor .octicon-link,
.markdown-body h5:hover .anchor .octicon-link,
.markdown-body h6:hover .anchor .octicon-link {
display: inline-block;
}
.markdown-body h1 {
padding-bottom: 0.3em;
font-size: 2.25em;
line-height: 1.2;
border-bottom: 1px solid #eee;
}
.markdown-body h2 {
padding-bottom: 0.3em;
font-size: 1.75em;
line-height: 1.225;
border-bottom: 1px solid #eee;
}
.markdown-body h3 {
font-size: 1.5em;
line-height: 1.43;
}
.markdown-body h4 {
font-size: 1.25em;
}
.markdown-body h5 {
font-size: 1em;
}
.markdown-body h6 {
font-size: 1em;
color: #777;
}
.markdown-body p,
.markdown-body blockquote,
.markdown-body ul,
.markdown-body ol,
.markdown-body dl,
.markdown-body table,
.markdown-body pre {
margin-top: 0;
margin-bottom: 16px;
}
.markdown-body hr {
height: 4px;
padding: 0;
margin: 16px 0;
background-color: #e7e7e7;
border: 0 none;
}
.markdown-body ul,
.markdown-body ol {
padding-left: 2em;
}
.markdown-body ul ul,
.markdown-body ul ol,
.markdown-body ol ol,
.markdown-body ol ul {
margin-top: 0;
margin-bottom: 0;
}
.markdown-body li>p {
margin-top: 16px;
}
.markdown-body dl {
padding: 0;
}
.markdown-body dl dt {
padding: 0;
margin-top: 16px;
font-size: 1em;
font-style: italic;
font-weight: bold;
}
.markdown-body dl dd {
padding: 0 16px;
margin-bottom: 16px;
}
.markdown-body blockquote {
padding: 0 15px;
color: #777;
border-left: 4px solid #ddd;
}
.markdown-body blockquote>:first-child {
margin-top: 0;
}
.markdown-body blockquote>:last-child {
margin-bottom: 0;
}
.markdown-body table {
display: block;
width: 100%;
overflow: auto;
word-break: normal;
word-break: keep-all;
}
.markdown-body table th {
font-weight: bold;
}
.markdown-body table th,
.markdown-body table td {
padding: 6px 13px;
border: 1px solid #ddd;
}
.markdown-body table tr {
background-color: #fff;
border-top: 1px solid #ccc;
}
.markdown-body table tr:nth-child(2n) {
background-color: #f8f8f8;
}
.markdown-body img {
max-width: 100%;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.markdown-body code {
padding: 0;
padding-top: 0.2em;
padding-bottom: 0.2em;
margin: 0;
font-size: 85%;
background-color: rgba(0,0,0,0.04);
border-radius: 3px;
}
.markdown-body code:before,
.markdown-body code:after {
letter-spacing: -0.2em;
content: "\00a0";
}
.markdown-body pre>code {
padding: 0;
margin: 0;
font-size: 100%;
word-break: normal;
white-space: pre;
background: transparent;
border: 0;
}
.markdown-body .highlight {
margin-bottom: 16px;
}
.markdown-body .highlight pre,
.markdown-body pre {
padding: 16px;
overflow: auto;
font-size: 85%;
line-height: 1.45;
background-color: #f7f7f7;
border-radius: 3px;
}
.markdown-body .highlight pre {
margin-bottom: 0;
word-break: normal;
}
.markdown-body pre {
word-wrap: normal;
}
.markdown-body pre code {
display: inline;
max-width: initial;
padding: 0;
margin: 0;
overflow: initial;
line-height: inherit;
word-wrap: normal;
background-color: transparent;
border: 0;
}
.markdown-body pre code:before,
.markdown-body pre code:after {
content: normal;
}
.markdown-body .highlight {
background: #fff;
}
.markdown-body .highlight .h {
color: #333;
font-style: normal;
font-weight: normal;
}
.markdown-body .highlight .mf,
.markdown-body .highlight .mh,
.markdown-body .highlight .mi,
.markdown-body .highlight .mo,
.markdown-body .highlight .il,
.markdown-body .highlight .m {
color: #945277;
}
.markdown-body .highlight .s,
.markdown-body .highlight .sb,
.markdown-body .highlight .sc,
.markdown-body .highlight .sd,
.markdown-body .highlight .s2,
.markdown-body .highlight .se,
.markdown-body .highlight .sh,
.markdown-body .highlight .si,
.markdown-body .highlight .sx,
.markdown-body .highlight .s1 {
color: #df5000;
}
.markdown-body .highlight .kc,
.markdown-body .highlight .kd,
.markdown-body .highlight .kn,
.markdown-body .highlight .kp,
.markdown-body .highlight .kr,
.markdown-body .highlight .kt,
.markdown-body .highlight .k,
.markdown-body .highlight .o {
font-weight: bold;
}
.markdown-body .highlight .kt {
color: #458;
}
.markdown-body .highlight .c,
.markdown-body .highlight .cm,
.markdown-body .highlight .c1 {
color: #998;
font-style: italic;
}
.markdown-body .highlight .cp,
.markdown-body .highlight .cs,
.markdown-body .highlight .cp .h {
color: #999;
font-weight: bold;
}
.markdown-body .highlight .cs {
font-style: italic;
}
.markdown-body .highlight .n {
color: #333;
}
.markdown-body .highlight .na,
.markdown-body .highlight .nv,
.markdown-body .highlight .vc,
.markdown-body .highlight .vg,
.markdown-body .highlight .vi {
color: #008080;
}
.markdown-body .highlight .nb {
color: #0086B3;
}
.markdown-body .highlight .nc {
color: #458;
font-weight: bold;
}
.markdown-body .highlight .no {
color: #094e99;
}
.markdown-body .highlight .ni {
color: #800080;
}
.markdown-body .highlight .ne {
color: #990000;
font-weight: bold;
}
.markdown-body .highlight .nf {
color: #945277;
font-weight: bold;
}
.markdown-body .highlight .nn {
color: #555;
}
.markdown-body .highlight .nt {
color: #000080;
}
.markdown-body .highlight .err {
color: #a61717;
background-color: #e3d2d2;
}
.markdown-body .highlight .gd {
color: #000;
background-color: #fdd;
}
.markdown-body .highlight .gd .x {
color: #000;
background-color: #faa;
}
.markdown-body .highlight .ge {
font-style: italic;
}
.markdown-body .highlight .gr {
color: #aa0000;
}
.markdown-body .highlight .gh {
color: #999;
}
.markdown-body .highlight .gi {
color: #000;
background-color: #dfd;
}
.markdown-body .highlight .gi .x {
color: #000;
background-color: #afa;
}
.markdown-body .highlight .go {
color: #888;
}
.markdown-body .highlight .gp {
color: #555;
}
.markdown-body .highlight .gs {
font-weight: bold;
}
.markdown-body .highlight .gu {
color: #800080;
font-weight: bold;
}
.markdown-body .highlight .gt {
color: #aa0000;
}
.markdown-body .highlight .ow {
font-weight: bold;
}
.markdown-body .highlight .w {
color: #bbb;
}
.markdown-body .highlight .sr {
color: #017936;
}
.markdown-body .highlight .ss {
color: #8b467f;
}
.markdown-body .highlight .bp {
color: #999;
}
.markdown-body .highlight .gc {
color: #999;
background-color: #EAF2F5;
}
.markdown-body kbd {
background-color: #e7e7e7;
background-image: -webkit-linear-gradient(#fefefe, #e7e7e7);
background-image: linear-gradient(#fefefe, #e7e7e7);
background-repeat: repeat-x;
display: inline-block;
padding: 3px 5px;
font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace;
line-height: 10px;
color: #000;
border: 1px solid #cfcfcf;
border-radius: 2px;
}
.markdown-body .highlight .pl-coc,
.markdown-body .highlight .pl-entm,
.markdown-body .highlight .pl-eoa,
.markdown-body .highlight .pl-mai .pl-sf,
.markdown-body .highlight .pl-pdv,
.markdown-body .highlight .pl-sc,
.markdown-body .highlight .pl-sr,
.markdown-body .highlight .pl-v,
.markdown-body .highlight .pl-vpf {
color: #0086b3;
}
.markdown-body .highlight .pl-eoac,
.markdown-body .highlight .pl-mdht,
.markdown-body .highlight .pl-mi1,
.markdown-body .highlight .pl-mri,
.markdown-body .highlight .pl-va,
.markdown-body .highlight .pl-vpu {
color: #008080;
}
.markdown-body .highlight .pl-c,
.markdown-body .highlight .pl-pdc {
color: #b4b7b4;
font-style: italic;
}
.markdown-body .highlight .pl-k,
.markdown-body .highlight .pl-ko,
.markdown-body .highlight .pl-kolp,
.markdown-body .highlight .pl-mc,
.markdown-body .highlight .pl-mr,
.markdown-body .highlight .pl-ms,
.markdown-body .highlight .pl-s,
.markdown-body .highlight .pl-sok,
.markdown-body .highlight .pl-st {
color: #6e5494;
}
.markdown-body .highlight .pl-ef,
.markdown-body .highlight .pl-enf,
.markdown-body .highlight .pl-enm,
.markdown-body .highlight .pl-entc,
.markdown-body .highlight .pl-eoi,
.markdown-body .highlight .pl-sf,
.markdown-body .highlight .pl-smc {
color: #d12089;
}
.markdown-body .highlight .pl-ens,
.markdown-body .highlight .pl-eoai,
.markdown-body .highlight .pl-kos,
.markdown-body .highlight .pl-mh .pl-pdh,
.markdown-body .highlight .pl-mp,
.markdown-body .highlight .pl-pde,
.markdown-body .highlight .pl-stp {
color: #458;
}
.markdown-body .highlight .pl-enti {
color: #d12089;
font-weight: bold;
}
.markdown-body .highlight .pl-cce,
.markdown-body .highlight .pl-enc,
.markdown-body .highlight .pl-kou,
.markdown-body .highlight .pl-mq {
color: #f93;
}
.markdown-body .highlight .pl-mp1 .pl-sf {
color: #458;
font-weight: bold;
}
.markdown-body .highlight .pl-cos,
.markdown-body .highlight .pl-ent,
.markdown-body .highlight .pl-md,
.markdown-body .highlight .pl-mdhf,
.markdown-body .highlight .pl-ml,
.markdown-body .highlight .pl-pdc1,
.markdown-body .highlight .pl-pds,
.markdown-body .highlight .pl-s1,
.markdown-body .highlight .pl-scp,
.markdown-body .highlight .pl-sol {
color: #df5000;
}
.markdown-body .highlight .pl-c1,
.markdown-body .highlight .pl-cn,
.markdown-body .highlight .pl-pse,
.markdown-body .highlight .pl-pse .pl-s2,
.markdown-body .highlight .pl-vi {
color: #a31515;
}
.markdown-body .highlight .pl-mb,
.markdown-body .highlight .pl-pdb {
color: #df5000;
font-weight: bold;
}
.markdown-body .highlight .pl-mi,
.markdown-body .highlight .pl-pdi {
color: #6e5494;
font-style: italic;
}
.markdown-body .highlight .pl-ms1 {
background-color: #f5f5f5;
}
.markdown-body .highlight .pl-mdh,
.markdown-body .highlight .pl-mdi {
font-weight: bold;
}
.markdown-body .highlight .pl-mdr {
color: #0086b3;
font-weight: bold;
}
.markdown-body .highlight .pl-s2 {
color: #333;
}
.markdown-body .highlight .pl-ii {
background-color: #df5000;
color: #fff;
}
.markdown-body .highlight .pl-ib {
background-color: #f93;
}
.markdown-body .highlight .pl-id {
background-color: #a31515;
color: #fff;
}
.markdown-body .highlight .pl-iu {
background-color: #b4b7b4;
}
.markdown-body .highlight .pl-mo {
color: #969896;
}
.markdown-body .task-list-item {
list-style-type: none;
}
.markdown-body .task-list-item+.task-list-item {
margin-top: 3px;
}
.markdown-body .task-list-item input {
float: left;
margin: 0.3em 0 0.25em -1.6em;
vertical-align: middle;
}</style><title>YHExplorer</title></head><body><article class="markdown-body">
<h1>
<a id="user-content-yhexplorer说明" class="anchor" href="#yhexplorer%E8%AF%B4%E6%98%8E" aria-hidden="true"><span class="octicon octicon-link"></span></a>YHExplorer说明</h1>
<hr>
<h2>
<a id="user-content-主要结构" class="anchor" href="#%E4%B8%BB%E8%A6%81%E7%BB%93%E6%9E%84" aria-hidden="true"><span class="octicon octicon-link"></span></a>主要结构</h2>
<p>本次对Cordova封装后的主要内容如下图:
<a href="/Users/gaoqiangxu/Workspace/YHExplorer/YHExplorer_Document/Cordova_Frame.png" target="_blank"><img src="/Users/gaoqiangxu/Workspace/YHExplorer/YHExplorer_Document/Cordova_Frame.png" alt="1" style="max-width:100%;"></a></p>
<ul>
<li>
<strong>CordovaLib</strong>: Cordova的Native端</li>
<li>
<strong>cordova.js</strong>: Cordova的js端</li>
<li>
<strong>config.xml</strong>: Cordova的一些配置项</li>
<li>
<strong>Cordova Plugins</strong>: Cordova的插件,封装了需要使用的Native Api</li>
<li>
<strong>YHNative</strong>: 本地机能模块</li>
<li>
<strong>YHURLCache</strong>: WebView缓存模块</li>
<li>
<strong>YHLinkParser</strong>: 链接跳转解析模块</li>
<li>
<strong>YHExplorerView</strong>: 封装了简化使用的WebView</li>
<li>
<strong>WebViewProgressView</strong>: 封装了浏览进度条</li>
</ul>
<h2>
<a id="user-content-基本交互原理" class="anchor" href="#%E5%9F%BA%E6%9C%AC%E4%BA%A4%E4%BA%92%E5%8E%9F%E7%90%86" aria-hidden="true"><span class="octicon octicon-link"></span></a>基本交互原理</h2>
<p><a href="/Users/gaoqiangxu/Workspace/YHExplorer/YHExplorer_Document/YHExplorerFlow.png" target="_blank"><img src="/Users/gaoqiangxu/Workspace/YHExplorer/YHExplorer_Document/YHExplorerFlow.png" alt="2" style="max-width:100%;"></a></p>
<h4>
<a id="user-content-加载" class="anchor" href="#%E5%8A%A0%E8%BD%BD" aria-hidden="true"><span class="octicon octicon-link"></span></a>加载:</h4>
<ol>
<li><p>传递url给YHExplorerView,由UIWebView对html进行加载与渲染</p></li>
<li><p>在html加载完后,注入cordova.js,激活cordova;同时<code>yohoInterface</code>插件也被激活</p></li>
</ol>
<h4>
<a id="user-content-交互" class="anchor" href="#%E4%BA%A4%E4%BA%92" aria-hidden="true"><span class="octicon octicon-link"></span></a>交互:</h4>
<ol>
<li><p><strong>链接交互</strong>:当探测到链接跳转时,通过<code>UIWebViewDelegate</code>传递给<code>CDVYHInterface</code>插件,然后由<code>YHLinkParser</code>来解析链接,把链接和解析好的参数传递给<code>YHExplorerDelegate</code>,由<code>YHExplorerDelegate</code>来处理逻辑。</p></li>
<li><p><strong>js对象交互</strong>:网页加载后,在js端激活了<code>yohoInterface</code>插件对象,这个插件提供了一系列<code>Native API</code>,可以直接与<code>CDVYHInterface</code>来进行交互(通过cordova来实现桥接通讯的)。
通俗的讲,也就是提供了网页调用本地机能的可能。</p></li>
</ol>
<p><strong>注:</strong>这两种方式的区别就是触发方式不同,第一个是链接触发,第二个是页面js对象主动触发。</p>
<h2>
<a id="user-content-安装" class="anchor" href="#%E5%AE%89%E8%A3%85" aria-hidden="true"><span class="octicon octicon-link"></span></a>安装</h2>
<h6>
<a id="user-content-1-集成到工程" class="anchor" href="#1-%E9%9B%86%E6%88%90%E5%88%B0%E5%B7%A5%E7%A8%8B" aria-hidden="true"><span class="octicon octicon-link"></span></a>1. 集成到工程</h6>
<p><code>YHExplorer</code>目录拷贝并添加到工程即可。</p>
<p>添加后的代码结构如下图:</p>
<p><a href="/Users/gaoqiangxu/Workspace/YHExplorer/YHExplorer_Document/code_architecture.png" target="_blank"><img src="/Users/gaoqiangxu/Workspace/YHExplorer/YHExplorer_Document/code_architecture.png" alt="3" style="max-width:100%;"></a></p>
<p>这里提供了2种展示方式:</p>
<pre><code>a. Controller方式: 使用YHExplorerViewController
b. View方式: 使用YHExplorerView
</code></pre>
<p>按照需要二选一即可,两种使用方式类似。</p>
<h2>
<a id="user-content-调用展示" class="anchor" href="#%E8%B0%83%E7%94%A8%E5%B1%95%E7%A4%BA" aria-hidden="true"><span class="octicon octicon-link"></span></a>调用(展示)</h2>
<h6>
<a id="user-content-1-初始化" class="anchor" href="#1-%E5%88%9D%E5%A7%8B%E5%8C%96" aria-hidden="true"><span class="octicon octicon-link"></span></a>1. 初始化</h6>
<div class="highlight highlight-objc"><pre><span class="pl-c">// 一: 直接使用链接初始化</span>
YHExplorerViewController *webViewController = [[YHExplorerViewController <span class="pl-c1">alloc</span>] <span class="pl-c1">initWithUrl:</span><span class="pl-s"><span class="pl-pds">@"</span>http://www.baidu.com<span class="pl-pds">"</span></span>];
<span class="pl-c">// 二: 先初始化,后加载网页</span>
YHExplorerViewController *webViewController = [[YHExplorerViewController <span class="pl-c1">alloc</span>] <span class="pl-c1">init</span>];</pre></div>
<h6>
<a id="user-content-2-加载" class="anchor" href="#2-%E5%8A%A0%E8%BD%BD" aria-hidden="true"><span class="octicon octicon-link"></span></a>2. 加载</h6>
<div class="highlight highlight-objc"><pre>[webViewController <span class="pl-c1">loadWebUrl:</span>url];</pre></div>
<h2>
<a id="user-content-链接参数捕捉处理" class="anchor" href="#%E9%93%BE%E6%8E%A5%E5%8F%82%E6%95%B0%E6%8D%95%E6%8D%89%E5%A4%84%E7%90%86" aria-hidden="true"><span class="octicon octicon-link"></span></a>链接参数捕捉处理</h2>
<h6>
<a id="user-content-事件处理yhexplorerdelegate" class="anchor" href="#%E4%BA%8B%E4%BB%B6%E5%A4%84%E7%90%86yhexplorerdelegate" aria-hidden="true"><span class="octicon octicon-link"></span></a>事件处理(YHExplorerDelegate)</h6>
<ul>
<li>如探测到参数后,会触发下面的代理方法:</li>
</ul>
<div class="highlight highlight-objc"><pre><span class="pl-c">/**</span>
<span class="pl-c"> * webView探测到含有指定参数的回调</span>
<span class="pl-c"> *</span>
<span class="pl-c"> * @param params 参数</span>
<span class="pl-c"> */</span>
- (<span class="pl-k">void</span>)explorerDidDetectParameters:(<span class="pl-c1">NSDictionary</span> *)params
{
<span class="pl-c">// 获取 没有参数的原始链接</span>
<span class="pl-c1">NSString</span> *freshUrl = params[YHLinkParseResult_FreshUrlKey];
<span class="pl-c">// 获取 打开类型</span>
<span class="pl-c1">NSString</span> *openType = params[YHLinkParseResult_OpenByKey];
<span class="pl-c">// 获取 打开参数</span>
<span class="pl-c1">NSDictionary</span> *openParameters = params[YHLinkParseResult_OpenParametersKey];
<span class="pl-c">// 下面处理业务逻辑</span>
}</pre></div>
<h2>
<a id="user-content-缓存" class="anchor" href="#%E7%BC%93%E5%AD%98" aria-hidden="true"><span class="octicon octicon-link"></span></a>缓存</h2>
<p>如需使用缓存,务必在<code>application:didFinishLaunchingWithOptions</code>方法里面提前设置:</p>
<div class="highlight highlight-objc"><pre>- (<span class="pl-k">BOOL</span>)application:(UIApplication *)application didFinishLaunchingWithOptions:(<span class="pl-c1">NSDictionary</span> *)launchOptions {
<span class="pl-c">// Override point for customization after application launch.</span>
YHURLCache *urlCache = [[YHURLCache <span class="pl-c1">alloc</span>] <span class="pl-c1">initWithMemoryCapacity:</span><span class="pl-c1">0</span>
<span class="pl-c1">diskCapacity:</span><span class="pl-c1">200</span>*<span class="pl-c1">1024</span>*<span class="pl-c1">1024</span><span class="pl-c">// 200MB</span>
<span class="pl-c1">diskPath:</span><span class="pl-c1">nil</span>
<span class="pl-c1">cacheDuration:</span><span class="pl-c1">0</span>];
[YHURLCache <span class="pl-c1">setSharedURLCache:</span>urlCache];
<span class="pl-k">return</span> <span class="pl-c1">YES</span>;
}</pre></div>
<h2>
<a id="user-content-网页加载进度条" class="anchor" href="#%E7%BD%91%E9%A1%B5%E5%8A%A0%E8%BD%BD%E8%BF%9B%E5%BA%A6%E6%9D%A1" aria-hidden="true"><span class="octicon octicon-link"></span></a>网页加载进度条</h2>
<div class="highlight highlight-objc"><pre>self.webView.enableProgressBar = <span class="pl-c1">YES</span>;</pre></div>
<p>效果如下图:</p>
<p><a href="/Users/gaoqiangxu/Workspace/YHExplorer/YHExplorer_Document/progressView.gif" target="_blank"><img src="/Users/gaoqiangxu/Workspace/YHExplorer/YHExplorer_Document/progressView.gif" alt="4" style="max-width:100%;"></a></p>
</article></body></html>
\ No newline at end of file
... ...
<!-- [1]:Cordova_Frame.png =500x -->
<!-- [2]:YHExplorerFlow.png =500x -->
[1]:Cordova_Frame.png
[2]:YHExplorerFlow.png
[3]:code_architecture.png
[4]:progressView.gif
#YHExplorer说明
---
##主要结构
本次对Cordova封装后的主要内容如下图:
![1]
* **CordovaLib**: Cordova的Native端
* **cordova.js**: Cordova的js端
* **config.xml**: Cordova的一些配置项
* **Cordova Plugins**: Cordova的插件,封装了需要使用的Native Api
* **YHNative**: 本地机能模块
* **YHURLCache**: WebView缓存模块
* **YHLinkParser**: 链接跳转解析模块
* **YHExplorerView**: 封装了简化使用的WebView
* **WebViewProgressView**: 封装了浏览进度条
##基本交互原理
![2]
####加载:
1. 传递url给YHExplorerView,由UIWebView对html进行加载与渲染
2. 在html加载完后,注入cordova.js,激活cordova;同时`yohoInterface`插件也被激活
####交互:
1. **链接交互**:当探测到链接跳转时,通过`UIWebViewDelegate`传递给`CDVYHInterface`插件,然后由`YHLinkParser`来解析链接,把链接和解析好的参数传递给`YHExplorerDelegate`,由`YHExplorerDelegate`来处理逻辑。
2. **js对象交互**:网页加载后,在js端激活了`yohoInterface`插件对象,这个插件提供了一系列`Native API`,可以直接与`CDVYHInterface`来进行交互(通过cordova来实现桥接通讯的)。
通俗的讲,也就是提供了网页调用本地机能的可能。
**注:**这两种方式的区别就是触发方式不同,第一个是链接触发,第二个是页面js对象主动触发。
##安装
######1. 集成到工程
`YHExplorer`目录拷贝并添加到工程即可。
添加后的代码结构如下图:
![3]
这里提供了2种展示方式:
a. Controller方式: 使用YHExplorerViewController
b. View方式: 使用YHExplorerView
按照需要二选一即可,两种使用方式类似。
##调用(展示)
######1. 初始化
```objc
// 一: 直接使用链接初始化
YHExplorerViewController *webViewController = [[YHExplorerViewController alloc] initWithUrl:@"http://www.baidu.com"];
// 二: 先初始化,后加载网页
YHExplorerViewController *webViewController = [[YHExplorerViewController alloc] init];
```
######2. 加载
```objc
[webViewController loadWebUrl:url];
```
##链接参数捕捉处理
######事件处理(YHExplorerDelegate)
* 如探测到参数后,会触发下面的代理方法:
```objc
/**
* webView探测到含有指定参数的回调
*
* @param params 参数
*/
- (void)explorerDidDetectParameters:(NSDictionary *)params
{
// 获取 没有参数的原始链接
NSString *freshUrl = params[YHLinkParseResult_FreshUrlKey];
// 获取 打开类型
NSString *openType = params[YHLinkParseResult_OpenByKey];
// 获取 打开参数
NSDictionary *openParameters = params[YHLinkParseResult_OpenParametersKey];
// 下面处理业务逻辑
}
```
##缓存
如需使用缓存,务必在`application:didFinishLaunchingWithOptions`方法里面提前设置:
```objc
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
YHURLCache *urlCache = [[YHURLCache alloc] initWithMemoryCapacity:0
diskCapacity:200*1024*1024// 200MB
diskPath:nil
cacheDuration:0];
[YHURLCache setSharedURLCache:urlCache];
return YES;
}
```
##网页加载进度条
```objc
self.webView.enableProgressBar = YES;
```
效果如下图:
![4]
... ...
No preview for this file type
<!DOCTYPE html><html><head><meta charset="utf-8"><style>body {
width: 45em;
border: 1px solid #ddd;
outline: 1300px solid #fff;
margin: 16px auto;
}
body .markdown-body
{
padding: 30px;
}
@font-face {
font-family: octicons-anchor;
src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAYcAA0AAAAACjQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABMAAAABwAAAAca8vGTk9TLzIAAAFMAAAARAAAAFZG1VHVY21hcAAAAZAAAAA+AAABQgAP9AdjdnQgAAAB0AAAAAQAAAAEACICiGdhc3AAAAHUAAAACAAAAAj//wADZ2x5ZgAAAdwAAADRAAABEKyikaNoZWFkAAACsAAAAC0AAAA2AtXoA2hoZWEAAALgAAAAHAAAACQHngNFaG10eAAAAvwAAAAQAAAAEAwAACJsb2NhAAADDAAAAAoAAAAKALIAVG1heHAAAAMYAAAAHwAAACABEAB2bmFtZQAAAzgAAALBAAAFu3I9x/Nwb3N0AAAF/AAAAB0AAAAvaoFvbwAAAAEAAAAAzBdyYwAAAADP2IQvAAAAAM/bz7t4nGNgZGFgnMDAysDB1Ml0hoGBoR9CM75mMGLkYGBgYmBlZsAKAtJcUxgcPsR8iGF2+O/AEMPsznAYKMwIkgMA5REMOXicY2BgYGaAYBkGRgYQsAHyGMF8FgYFIM0ChED+h5j//yEk/3KoSgZGNgYYk4GRCUgwMaACRoZhDwCs7QgGAAAAIgKIAAAAAf//AAJ4nHWMMQrCQBBF/0zWrCCIKUQsTDCL2EXMohYGSSmorScInsRGL2DOYJe0Ntp7BK+gJ1BxF1stZvjz/v8DRghQzEc4kIgKwiAppcA9LtzKLSkdNhKFY3HF4lK69ExKslx7Xa+vPRVS43G98vG1DnkDMIBUgFN0MDXflU8tbaZOUkXUH0+U27RoRpOIyCKjbMCVejwypzJJG4jIwb43rfl6wbwanocrJm9XFYfskuVC5K/TPyczNU7b84CXcbxks1Un6H6tLH9vf2LRnn8Ax7A5WQAAAHicY2BkYGAA4teL1+yI57f5ysDNwgAC529f0kOmWRiYVgEpDgYmEA8AUzEKsQAAAHicY2BkYGB2+O/AEMPCAAJAkpEBFbAAADgKAe0EAAAiAAAAAAQAAAAEAAAAAAAAKgAqACoAiAAAeJxjYGRgYGBhsGFgYgABEMkFhAwM/xn0QAIAD6YBhwB4nI1Ty07cMBS9QwKlQapQW3VXySvEqDCZGbGaHULiIQ1FKgjWMxknMfLEke2A+IJu+wntrt/QbVf9gG75jK577Lg8K1qQPCfnnnt8fX1NRC/pmjrk/zprC+8D7tBy9DHgBXoWfQ44Av8t4Bj4Z8CLtBL9CniJluPXASf0Lm4CXqFX8Q84dOLnMB17N4c7tBo1AS/Qi+hTwBH4rwHHwN8DXqQ30XXAS7QaLwSc0Gn8NuAVWou/gFmnjLrEaEh9GmDdDGgL3B4JsrRPDU2hTOiMSuJUIdKQQayiAth69r6akSSFqIJuA19TrzCIaY8sIoxyrNIrL//pw7A2iMygkX5vDj+G+kuoLdX4GlGK/8Lnlz6/h9MpmoO9rafrz7ILXEHHaAx95s9lsI7AHNMBWEZHULnfAXwG9/ZqdzLI08iuwRloXE8kfhXYAvE23+23DU3t626rbs8/8adv+9DWknsHp3E17oCf+Z48rvEQNZ78paYM38qfk3v/u3l3u3GXN2Dmvmvpf1Srwk3pB/VSsp512bA/GG5i2WJ7wu430yQ5K3nFGiOqgtmSB5pJVSizwaacmUZzZhXLlZTq8qGGFY2YcSkqbth6aW1tRmlaCFs2016m5qn36SbJrqosG4uMV4aP2PHBmB3tjtmgN2izkGQyLWprekbIntJFing32a5rKWCN/SdSoga45EJykyQ7asZvHQ8PTm6cslIpwyeyjbVltNikc2HTR7YKh9LBl9DADC0U/jLcBZDKrMhUBfQBvXRzLtFtjU9eNHKin0x5InTqb8lNpfKv1s1xHzTXRqgKzek/mb7nB8RZTCDhGEX3kK/8Q75AmUM/eLkfA+0Hi908Kx4eNsMgudg5GLdRD7a84npi+YxNr5i5KIbW5izXas7cHXIMAau1OueZhfj+cOcP3P8MNIWLyYOBuxL6DRylJ4cAAAB4nGNgYoAALjDJyIAOWMCiTIxMLDmZedkABtIBygAAAA==) format('woff');
}
.markdown-body {
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
color: #333;
overflow: hidden;
font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;
font-size: 16px;
line-height: 1.6;
word-wrap: break-word;
}
.markdown-body a {
background: transparent;
}
.markdown-body a:active,
.markdown-body a:hover {
outline: 0;
}
.markdown-body strong {
font-weight: bold;
}
.markdown-body h1 {
font-size: 2em;
margin: 0.67em 0;
}
.markdown-body img {
border: 0;
}
.markdown-body hr {
-moz-box-sizing: content-box;
box-sizing: content-box;
height: 0;
}
.markdown-body pre {
overflow: auto;
}
.markdown-body code,
.markdown-body kbd,
.markdown-body pre {
font-family: monospace, monospace;
font-size: 1em;
}
.markdown-body input {
color: inherit;
font: inherit;
margin: 0;
}
.markdown-body html input[disabled] {
cursor: default;
}
.markdown-body input {
line-height: normal;
}
.markdown-body input[type="checkbox"] {
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 0;
}
.markdown-body table {
border-collapse: collapse;
border-spacing: 0;
}
.markdown-body td,
.markdown-body th {
padding: 0;
}
.markdown-body * {
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.markdown-body input {
font: 13px/1.4 Helvetica, arial, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol";
}
.markdown-body a {
color: #4183c4;
text-decoration: none;
}
.markdown-body a:hover,
.markdown-body a:focus,
.markdown-body a:active {
text-decoration: underline;
}
.markdown-body hr {
height: 0;
margin: 15px 0;
overflow: hidden;
background: transparent;
border: 0;
border-bottom: 1px solid #ddd;
}
.markdown-body hr:before {
display: table;
content: "";
}
.markdown-body hr:after {
display: table;
clear: both;
content: "";
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
margin-top: 15px;
margin-bottom: 15px;
line-height: 1.1;
}
.markdown-body h1 {
font-size: 30px;
}
.markdown-body h2 {
font-size: 21px;
}
.markdown-body h3 {
font-size: 16px;
}
.markdown-body h4 {
font-size: 14px;
}
.markdown-body h5 {
font-size: 12px;
}
.markdown-body h6 {
font-size: 11px;
}
.markdown-body blockquote {
margin: 0;
}
.markdown-body ul,
.markdown-body ol {
padding: 0;
margin-top: 0;
margin-bottom: 0;
}
.markdown-body ol ol,
.markdown-body ul ol {
list-style-type: lower-roman;
}
.markdown-body ul ul ol,
.markdown-body ul ol ol,
.markdown-body ol ul ol,
.markdown-body ol ol ol {
list-style-type: lower-alpha;
}
.markdown-body dd {
margin-left: 0;
}
.markdown-body code {
font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace;
}
.markdown-body pre {
margin-top: 0;
margin-bottom: 0;
font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace;
}
.markdown-body .octicon {
font: normal normal 16px octicons-anchor;
line-height: 1;
display: inline-block;
text-decoration: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.markdown-body .octicon-link:before {
content: '\f05c';
}
.markdown-body>*:first-child {
margin-top: 0 !important;
}
.markdown-body>*:last-child {
margin-bottom: 0 !important;
}
.markdown-body .anchor {
position: absolute;
top: 0;
bottom: 0;
left: 0;
display: block;
padding-right: 6px;
padding-left: 30px;
margin-left: -30px;
}
.markdown-body .anchor:focus {
outline: none;
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
position: relative;
margin-top: 1em;
margin-bottom: 16px;
font-weight: bold;
line-height: 1.4;
}
.markdown-body h1 .octicon-link,
.markdown-body h2 .octicon-link,
.markdown-body h3 .octicon-link,
.markdown-body h4 .octicon-link,
.markdown-body h5 .octicon-link,
.markdown-body h6 .octicon-link {
display: none;
color: #000;
vertical-align: middle;
}
.markdown-body h1:hover .anchor,
.markdown-body h2:hover .anchor,
.markdown-body h3:hover .anchor,
.markdown-body h4:hover .anchor,
.markdown-body h5:hover .anchor,
.markdown-body h6:hover .anchor {
padding-left: 8px;
margin-left: -30px;
line-height: 1;
text-decoration: none;
}
.markdown-body h1:hover .anchor .octicon-link,
.markdown-body h2:hover .anchor .octicon-link,
.markdown-body h3:hover .anchor .octicon-link,
.markdown-body h4:hover .anchor .octicon-link,
.markdown-body h5:hover .anchor .octicon-link,
.markdown-body h6:hover .anchor .octicon-link {
display: inline-block;
}
.markdown-body h1 {
padding-bottom: 0.3em;
font-size: 2.25em;
line-height: 1.2;
border-bottom: 1px solid #eee;
}
.markdown-body h2 {
padding-bottom: 0.3em;
font-size: 1.75em;
line-height: 1.225;
border-bottom: 1px solid #eee;
}
.markdown-body h3 {
font-size: 1.5em;
line-height: 1.43;
}
.markdown-body h4 {
font-size: 1.25em;
}
.markdown-body h5 {
font-size: 1em;
}
.markdown-body h6 {
font-size: 1em;
color: #777;
}
.markdown-body p,
.markdown-body blockquote,
.markdown-body ul,
.markdown-body ol,
.markdown-body dl,
.markdown-body table,
.markdown-body pre {
margin-top: 0;
margin-bottom: 16px;
}
.markdown-body hr {
height: 4px;
padding: 0;
margin: 16px 0;
background-color: #e7e7e7;
border: 0 none;
}
.markdown-body ul,
.markdown-body ol {
padding-left: 2em;
}
.markdown-body ul ul,
.markdown-body ul ol,
.markdown-body ol ol,
.markdown-body ol ul {
margin-top: 0;
margin-bottom: 0;
}
.markdown-body li>p {
margin-top: 16px;
}
.markdown-body dl {
padding: 0;
}
.markdown-body dl dt {
padding: 0;
margin-top: 16px;
font-size: 1em;
font-style: italic;
font-weight: bold;
}
.markdown-body dl dd {
padding: 0 16px;
margin-bottom: 16px;
}
.markdown-body blockquote {
padding: 0 15px;
color: #777;
border-left: 4px solid #ddd;
}
.markdown-body blockquote>:first-child {
margin-top: 0;
}
.markdown-body blockquote>:last-child {
margin-bottom: 0;
}
.markdown-body table {
display: block;
width: 100%;
overflow: auto;
word-break: normal;
word-break: keep-all;
}
.markdown-body table th {
font-weight: bold;
}
.markdown-body table th,
.markdown-body table td {
padding: 6px 13px;
border: 1px solid #ddd;
}
.markdown-body table tr {
background-color: #fff;
border-top: 1px solid #ccc;
}
.markdown-body table tr:nth-child(2n) {
background-color: #f8f8f8;
}
.markdown-body img {
max-width: 100%;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.markdown-body code {
padding: 0;
padding-top: 0.2em;
padding-bottom: 0.2em;
margin: 0;
font-size: 85%;
background-color: rgba(0,0,0,0.04);
border-radius: 3px;
}
.markdown-body code:before,
.markdown-body code:after {
letter-spacing: -0.2em;
content: "\00a0";
}
.markdown-body pre>code {
padding: 0;
margin: 0;
font-size: 100%;
word-break: normal;
white-space: pre;
background: transparent;
border: 0;
}
.markdown-body .highlight {
margin-bottom: 16px;
}
.markdown-body .highlight pre,
.markdown-body pre {
padding: 16px;
overflow: auto;
font-size: 85%;
line-height: 1.45;
background-color: #f7f7f7;
border-radius: 3px;
}
.markdown-body .highlight pre {
margin-bottom: 0;
word-break: normal;
}
.markdown-body pre {
word-wrap: normal;
}
.markdown-body pre code {
display: inline;
max-width: initial;
padding: 0;
margin: 0;
overflow: initial;
line-height: inherit;
word-wrap: normal;
background-color: transparent;
border: 0;
}
.markdown-body pre code:before,
.markdown-body pre code:after {
content: normal;
}
.markdown-body .highlight {
background: #fff;
}
.markdown-body .highlight .h {
color: #333;
font-style: normal;
font-weight: normal;
}
.markdown-body .highlight .mf,
.markdown-body .highlight .mh,
.markdown-body .highlight .mi,
.markdown-body .highlight .mo,
.markdown-body .highlight .il,
.markdown-body .highlight .m {
color: #945277;
}
.markdown-body .highlight .s,
.markdown-body .highlight .sb,
.markdown-body .highlight .sc,
.markdown-body .highlight .sd,
.markdown-body .highlight .s2,
.markdown-body .highlight .se,
.markdown-body .highlight .sh,
.markdown-body .highlight .si,
.markdown-body .highlight .sx,
.markdown-body .highlight .s1 {
color: #df5000;
}
.markdown-body .highlight .kc,
.markdown-body .highlight .kd,
.markdown-body .highlight .kn,
.markdown-body .highlight .kp,
.markdown-body .highlight .kr,
.markdown-body .highlight .kt,
.markdown-body .highlight .k,
.markdown-body .highlight .o {
font-weight: bold;
}
.markdown-body .highlight .kt {
color: #458;
}
.markdown-body .highlight .c,
.markdown-body .highlight .cm,
.markdown-body .highlight .c1 {
color: #998;
font-style: italic;
}
.markdown-body .highlight .cp,
.markdown-body .highlight .cs,
.markdown-body .highlight .cp .h {
color: #999;
font-weight: bold;
}
.markdown-body .highlight .cs {
font-style: italic;
}
.markdown-body .highlight .n {
color: #333;
}
.markdown-body .highlight .na,
.markdown-body .highlight .nv,
.markdown-body .highlight .vc,
.markdown-body .highlight .vg,
.markdown-body .highlight .vi {
color: #008080;
}
.markdown-body .highlight .nb {
color: #0086B3;
}
.markdown-body .highlight .nc {
color: #458;
font-weight: bold;
}
.markdown-body .highlight .no {
color: #094e99;
}
.markdown-body .highlight .ni {
color: #800080;
}
.markdown-body .highlight .ne {
color: #990000;
font-weight: bold;
}
.markdown-body .highlight .nf {
color: #945277;
font-weight: bold;
}
.markdown-body .highlight .nn {
color: #555;
}
.markdown-body .highlight .nt {
color: #000080;
}
.markdown-body .highlight .err {
color: #a61717;
background-color: #e3d2d2;
}
.markdown-body .highlight .gd {
color: #000;
background-color: #fdd;
}
.markdown-body .highlight .gd .x {
color: #000;
background-color: #faa;
}
.markdown-body .highlight .ge {
font-style: italic;
}
.markdown-body .highlight .gr {
color: #aa0000;
}
.markdown-body .highlight .gh {
color: #999;
}
.markdown-body .highlight .gi {
color: #000;
background-color: #dfd;
}
.markdown-body .highlight .gi .x {
color: #000;
background-color: #afa;
}
.markdown-body .highlight .go {
color: #888;
}
.markdown-body .highlight .gp {
color: #555;
}
.markdown-body .highlight .gs {
font-weight: bold;
}
.markdown-body .highlight .gu {
color: #800080;
font-weight: bold;
}
.markdown-body .highlight .gt {
color: #aa0000;
}
.markdown-body .highlight .ow {
font-weight: bold;
}
.markdown-body .highlight .w {
color: #bbb;
}
.markdown-body .highlight .sr {
color: #017936;
}
.markdown-body .highlight .ss {
color: #8b467f;
}
.markdown-body .highlight .bp {
color: #999;
}
.markdown-body .highlight .gc {
color: #999;
background-color: #EAF2F5;
}
.markdown-body kbd {
background-color: #e7e7e7;
background-image: -webkit-linear-gradient(#fefefe, #e7e7e7);
background-image: linear-gradient(#fefefe, #e7e7e7);
background-repeat: repeat-x;
display: inline-block;
padding: 3px 5px;
font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace;
line-height: 10px;
color: #000;
border: 1px solid #cfcfcf;
border-radius: 2px;
}
.markdown-body .highlight .pl-coc,
.markdown-body .highlight .pl-entm,
.markdown-body .highlight .pl-eoa,
.markdown-body .highlight .pl-mai .pl-sf,
.markdown-body .highlight .pl-pdv,
.markdown-body .highlight .pl-sc,
.markdown-body .highlight .pl-sr,
.markdown-body .highlight .pl-v,
.markdown-body .highlight .pl-vpf {
color: #0086b3;
}
.markdown-body .highlight .pl-eoac,
.markdown-body .highlight .pl-mdht,
.markdown-body .highlight .pl-mi1,
.markdown-body .highlight .pl-mri,
.markdown-body .highlight .pl-va,
.markdown-body .highlight .pl-vpu {
color: #008080;
}
.markdown-body .highlight .pl-c,
.markdown-body .highlight .pl-pdc {
color: #b4b7b4;
font-style: italic;
}
.markdown-body .highlight .pl-k,
.markdown-body .highlight .pl-ko,
.markdown-body .highlight .pl-kolp,
.markdown-body .highlight .pl-mc,
.markdown-body .highlight .pl-mr,
.markdown-body .highlight .pl-ms,
.markdown-body .highlight .pl-s,
.markdown-body .highlight .pl-sok,
.markdown-body .highlight .pl-st {
color: #6e5494;
}
.markdown-body .highlight .pl-ef,
.markdown-body .highlight .pl-enf,
.markdown-body .highlight .pl-enm,
.markdown-body .highlight .pl-entc,
.markdown-body .highlight .pl-eoi,
.markdown-body .highlight .pl-sf,
.markdown-body .highlight .pl-smc {
color: #d12089;
}
.markdown-body .highlight .pl-ens,
.markdown-body .highlight .pl-eoai,
.markdown-body .highlight .pl-kos,
.markdown-body .highlight .pl-mh .pl-pdh,
.markdown-body .highlight .pl-mp,
.markdown-body .highlight .pl-pde,
.markdown-body .highlight .pl-stp {
color: #458;
}
.markdown-body .highlight .pl-enti {
color: #d12089;
font-weight: bold;
}
.markdown-body .highlight .pl-cce,
.markdown-body .highlight .pl-enc,
.markdown-body .highlight .pl-kou,
.markdown-body .highlight .pl-mq {
color: #f93;
}
.markdown-body .highlight .pl-mp1 .pl-sf {
color: #458;
font-weight: bold;
}
.markdown-body .highlight .pl-cos,
.markdown-body .highlight .pl-ent,
.markdown-body .highlight .pl-md,
.markdown-body .highlight .pl-mdhf,
.markdown-body .highlight .pl-ml,
.markdown-body .highlight .pl-pdc1,
.markdown-body .highlight .pl-pds,
.markdown-body .highlight .pl-s1,
.markdown-body .highlight .pl-scp,
.markdown-body .highlight .pl-sol {
color: #df5000;
}
.markdown-body .highlight .pl-c1,
.markdown-body .highlight .pl-cn,
.markdown-body .highlight .pl-pse,
.markdown-body .highlight .pl-pse .pl-s2,
.markdown-body .highlight .pl-vi {
color: #a31515;
}
.markdown-body .highlight .pl-mb,
.markdown-body .highlight .pl-pdb {
color: #df5000;
font-weight: bold;
}
.markdown-body .highlight .pl-mi,
.markdown-body .highlight .pl-pdi {
color: #6e5494;
font-style: italic;
}
.markdown-body .highlight .pl-ms1 {
background-color: #f5f5f5;
}
.markdown-body .highlight .pl-mdh,
.markdown-body .highlight .pl-mdi {
font-weight: bold;
}
.markdown-body .highlight .pl-mdr {
color: #0086b3;
font-weight: bold;
}
.markdown-body .highlight .pl-s2 {
color: #333;
}
.markdown-body .highlight .pl-ii {
background-color: #df5000;
color: #fff;
}
.markdown-body .highlight .pl-ib {
background-color: #f93;
}
.markdown-body .highlight .pl-id {
background-color: #a31515;
color: #fff;
}
.markdown-body .highlight .pl-iu {
background-color: #b4b7b4;
}
.markdown-body .highlight .pl-mo {
color: #969896;
}
.markdown-body .task-list-item {
list-style-type: none;
}
.markdown-body .task-list-item+.task-list-item {
margin-top: 3px;
}
.markdown-body .task-list-item input {
float: left;
margin: 0.3em 0 0.25em -1.6em;
vertical-align: middle;
}</style><title>YHExplorer前端调用说明</title></head><body><article class="markdown-body"><h3>
<a id="user-content-基本使用" class="anchor" href="#%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8" aria-hidden="true"><span class="octicon octicon-link"></span></a>基本使用</h3>
<div class="highlight highlight-javascript"><pre><span class="pl-c">&lt;!--</span> 组装参数,下面是基本参数结构 <span class="pl-c">--&gt;</span>
<span class="pl-k">var</span> params <span class="pl-k">=</span> { <span class="pl-s"><span class="pl-pds">"</span>ability<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-s"><span class="pl-pds">"</span>action<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>options<span class="pl-pds">"</span></span><span class="pl-k">:</span>{<span class="pl-s"><span class="pl-pds">"</span>optionKey<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-s"><span class="pl-pds">"</span>optionValue<span class="pl-pds">"</span></span>} };
<span class="pl-c">&lt;!--</span> 触发机能 <span class="pl-c">--&gt;</span>
yohoInterface.triggerEvent(onSuccess, onFail, params);</pre></div>
<p><code>onSuccess</code>回调里面会传递结果。</p>
<h3>
<a id="user-content-具体定义" class="anchor" href="#%E5%85%B7%E4%BD%93%E5%AE%9A%E4%B9%89" aria-hidden="true"><span class="octicon octicon-link"></span></a>具体定义</h3>
<h5>
<a id="user-content-1-摄像头" class="anchor" href="#1-%E6%91%84%E5%83%8F%E5%A4%B4" aria-hidden="true"><span class="octicon octicon-link"></span></a>1. 摄像头</h5>
<ul>
<li>拍照/访问相册</li>
</ul>
<div class="highlight highlight-javascript"><pre><span class="pl-c">&lt;!--</span>
quality(照片质量) <span class="pl-c1">0</span><span class="pl-k">-</span><span class="pl-c1">100</span>
pictureSourceType(照片源)<span class="pl-k">:</span> <span class="pl-c1">1</span>. 访问相册 SAVEDPHOTOALBUM <span class="pl-c1">2</span>. 摄像头 CAMERA
targetSize(照片尺寸,单位:像素)<span class="pl-k">:</span> 如果其中某个设为<span class="pl-c1">0</span>,则认为等比缩放
<span class="pl-c">--&gt;</span>
<span class="pl-k">var</span> params <span class="pl-k">=</span> { <span class="pl-s"><span class="pl-pds">"</span>Native_Camera<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-s"><span class="pl-pds">"</span>takePicture<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>options<span class="pl-pds">"</span></span><span class="pl-k">:</span>{ <span class="pl-s"><span class="pl-pds">"</span>quality<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-c1">75</span>, <span class="pl-s"><span class="pl-pds">"</span>pictureSourceType<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-s"><span class="pl-pds">"</span>CAMERA<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>targetSize<span class="pl-pds">"</span></span><span class="pl-k">:</span>{ <span class="pl-s"><span class="pl-pds">"</span>width<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-c1">100</span>, <span class="pl-s"><span class="pl-pds">"</span>height<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-c1">100</span> } } };</pre></div>
<ul>
<li>展示获取的照片Example</li>
</ul>
<div class="highlight highlight-javascript"><pre><span class="pl-k">function</span> <span class="pl-en">onSuccess</span>(<span class="pl-smi">imageData</span>) {
<span class="pl-k">var</span> image <span class="pl-k">=</span> <span class="pl-c1">document</span>.<span class="pl-c1">getElementById</span>(<span class="pl-s"><span class="pl-pds">'</span>myImage<span class="pl-pds">'</span></span>);
image.<span class="pl-c1">src</span> <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">"</span>data:image/jpeg;base64,<span class="pl-pds">"</span></span> <span class="pl-k">+</span> imageData;
}</pre></div>
<h5>
<a id="user-content-2-lbs" class="anchor" href="#2-lbs" aria-hidden="true"><span class="octicon octicon-link"></span></a>2. LBS</h5>
<ul>
<li>获取Location</li>
</ul>
<div class="highlight highlight-javascript"><pre><span class="pl-k">var</span> params <span class="pl-k">=</span> { <span class="pl-s"><span class="pl-pds">"</span>Native_LBS<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-s"><span class="pl-pds">"</span>getLocation<span class="pl-pds">"</span></span> };
<span class="pl-c">&lt;!--</span> 回调Example<span class="pl-k">:</span> <span class="pl-c">--&gt;</span>
<span class="pl-k">function</span> <span class="pl-en">onSuccess</span>(<span class="pl-smi">coordinate</span>) {
<span class="pl-c1">alert</span>(<span class="pl-s"><span class="pl-pds">'</span>Coordinate Latitude: <span class="pl-pds">'</span></span> <span class="pl-k">+</span> coordinate.latitude <span class="pl-k">+</span> <span class="pl-s"><span class="pl-pds">'</span><span class="pl-cce">\n</span><span class="pl-pds">'</span></span> <span class="pl-k">+</span>
<span class="pl-s"><span class="pl-pds">'</span>Coordinate Longitude: <span class="pl-pds">'</span></span> <span class="pl-k">+</span> coordinate.longitude);
};</pre></div>
<ul>
<li>获取所在地理位置信息</li>
</ul>
<div class="highlight highlight-javascript"><pre><span class="pl-k">var</span> params <span class="pl-k">=</span> { <span class="pl-s"><span class="pl-pds">"</span>Native_LBS<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-s"><span class="pl-pds">"</span>getLocationDetail<span class="pl-pds">"</span></span> };
<span class="pl-c">&lt;!--</span> 回调Example<span class="pl-k">:</span>
国家 <span class="pl-k">-</span> placemark.country
国家代号 <span class="pl-k">-</span> placemark.countryCode
城市 <span class="pl-k">-</span> placemark.city
<span class="pl-k">-</span> placemark.state
街道 <span class="pl-k">-</span> placemark.street
<span class="pl-k">-</span> placemark.sublocality
完整地址名称 <span class="pl-k">-</span> placemark.<span class="pl-c1">name</span>
<span class="pl-c">--&gt;</span>
<span class="pl-k">function</span> <span class="pl-en">onSuccess</span>(<span class="pl-smi">placemark</span>) {
<span class="pl-c1">alert</span>(<span class="pl-s"><span class="pl-pds">'</span>name: <span class="pl-pds">'</span></span> <span class="pl-k">+</span> placemark.<span class="pl-c1">name</span> <span class="pl-k">+</span> <span class="pl-s"><span class="pl-pds">'</span><span class="pl-cce">\n</span><span class="pl-pds">'</span></span> <span class="pl-k">+</span>
<span class="pl-s"><span class="pl-pds">'</span>countryCode: <span class="pl-pds">'</span></span> <span class="pl-k">+</span> placemark.countryCode <span class="pl-k">+</span> <span class="pl-s"><span class="pl-pds">'</span><span class="pl-cce">\n</span><span class="pl-pds">'</span></span> <span class="pl-k">+</span>
<span class="pl-s"><span class="pl-pds">'</span>country: <span class="pl-pds">'</span></span> <span class="pl-k">+</span> placemark.country <span class="pl-k">+</span> <span class="pl-s"><span class="pl-pds">'</span><span class="pl-cce">\n</span><span class="pl-pds">'</span></span> <span class="pl-k">+</span>
<span class="pl-s"><span class="pl-pds">'</span>state: <span class="pl-pds">'</span></span> <span class="pl-k">+</span> placemark.state <span class="pl-k">+</span> <span class="pl-s"><span class="pl-pds">'</span><span class="pl-cce">\n</span><span class="pl-pds">'</span></span> <span class="pl-k">+</span>
<span class="pl-s"><span class="pl-pds">'</span>city: <span class="pl-pds">'</span></span> <span class="pl-k">+</span> placemark.city <span class="pl-k">+</span> <span class="pl-s"><span class="pl-pds">'</span><span class="pl-cce">\n</span><span class="pl-pds">'</span></span> <span class="pl-k">+</span>
<span class="pl-s"><span class="pl-pds">'</span>sublocality: <span class="pl-pds">'</span></span> <span class="pl-k">+</span> placemark.sublocality <span class="pl-k">+</span> <span class="pl-s"><span class="pl-pds">'</span><span class="pl-cce">\n</span><span class="pl-pds">'</span></span> <span class="pl-k">+</span>
<span class="pl-s"><span class="pl-pds">'</span>street: <span class="pl-pds">'</span></span> <span class="pl-k">+</span> placemark.street);
};</pre></div>
<h5>
<a id="user-content-3-device" class="anchor" href="#3-device" aria-hidden="true"><span class="octicon octicon-link"></span></a>3. Device</h5>
<ul>
<li>获取设备信息</li>
</ul>
<div class="highlight highlight-javascript"><pre><span class="pl-k">var</span> params <span class="pl-k">=</span> { <span class="pl-s"><span class="pl-pds">"</span>Native_Device<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-s"><span class="pl-pds">"</span>getDeviceInfo<span class="pl-pds">"</span></span> };
<span class="pl-c">&lt;!--</span> 回调Example<span class="pl-k">:</span> <span class="pl-c">--&gt;</span>
<span class="pl-k">function</span> <span class="pl-en">onSuccess</span>(<span class="pl-smi">device</span>) {
<span class="pl-c1">alert</span>(<span class="pl-s"><span class="pl-pds">'</span>Model: <span class="pl-pds">'</span></span> <span class="pl-k">+</span> device.model <span class="pl-k">+</span> <span class="pl-s"><span class="pl-pds">'</span><span class="pl-cce">\n</span><span class="pl-pds">'</span></span> <span class="pl-k">+</span>
<span class="pl-s"><span class="pl-pds">'</span>Platform: <span class="pl-pds">'</span></span> <span class="pl-k">+</span> device.<span class="pl-c1">platform</span> <span class="pl-k">+</span> <span class="pl-s"><span class="pl-pds">'</span><span class="pl-cce">\n</span><span class="pl-pds">'</span></span> <span class="pl-k">+</span>
<span class="pl-s"><span class="pl-pds">'</span>OSVersion: <span class="pl-pds">'</span></span> <span class="pl-k">+</span> device.<span class="pl-c1">version</span>);
};</pre></div>
<h5>
<a id="user-content-4-media" class="anchor" href="#4-media" aria-hidden="true"><span class="octicon octicon-link"></span></a>4. Media</h5>
<ul>
<li>调用iOS媒体播放器</li>
</ul>
<div class="highlight highlight-javascript"><pre><span class="pl-k">var</span> params <span class="pl-k">=</span> { <span class="pl-s"><span class="pl-pds">"</span>Native_Media<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-s"><span class="pl-pds">"</span>playMedia<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>options<span class="pl-pds">"</span></span><span class="pl-k">:</span>{ <span class="pl-s"><span class="pl-pds">"</span>url<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-s"><span class="pl-pds">"</span>http://xxxxxxx.mp4<span class="pl-pds">"</span></span> } };</pre></div>
<h5>
<a id="user-content-5-传感器" class="anchor" href="#5-%E4%BC%A0%E6%84%9F%E5%99%A8" aria-hidden="true"><span class="octicon octicon-link"></span></a>5. 传感器</h5>
<ul>
<li>震动</li>
</ul>
<div class="highlight highlight-javascript"><pre><span class="pl-c">&lt;!--</span> duration为震动时长 <span class="pl-c">--&gt;</span>
<span class="pl-k">var</span> params <span class="pl-k">=</span> { <span class="pl-s"><span class="pl-pds">"</span>Native_Motion<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-s"><span class="pl-pds">"</span>vibrate<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>options<span class="pl-pds">"</span></span><span class="pl-k">:</span>{ <span class="pl-s"><span class="pl-pds">"</span>duration<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-c1">1.2</span> } };</pre></div>
<ul>
<li>获取加速计状态</li>
</ul>
<div class="highlight highlight-javascript"><pre><span class="pl-c">&lt;!--</span> period为观察间隔,单位是毫秒 <span class="pl-c">--&gt;</span>
<span class="pl-k">var</span> params <span class="pl-k">=</span> { <span class="pl-s"><span class="pl-pds">"</span>Native_Motion<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-s"><span class="pl-pds">"</span>watchAcceleration<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>options<span class="pl-pds">"</span></span><span class="pl-k">:</span>{ <span class="pl-s"><span class="pl-pds">"</span>period<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-c1">1000</span> } };
<span class="pl-c">&lt;!--</span> 回调Example<span class="pl-k">:</span> <span class="pl-c">--&gt;</span>
<span class="pl-k">function</span> <span class="pl-en">onSuccess</span>(<span class="pl-smi">acceleration</span>) {
<span class="pl-c1">alert</span>(<span class="pl-s"><span class="pl-pds">'</span>Acceleration X: <span class="pl-pds">'</span></span> <span class="pl-k">+</span> acceleration.<span class="pl-c1">x</span> <span class="pl-k">+</span> <span class="pl-s"><span class="pl-pds">'</span><span class="pl-cce">\n</span><span class="pl-pds">'</span></span> <span class="pl-k">+</span>
<span class="pl-s"><span class="pl-pds">'</span>Acceleration Y: <span class="pl-pds">'</span></span> <span class="pl-k">+</span> acceleration.<span class="pl-c1">y</span> <span class="pl-k">+</span> <span class="pl-s"><span class="pl-pds">'</span><span class="pl-cce">\n</span><span class="pl-pds">'</span></span> <span class="pl-k">+</span>
<span class="pl-s"><span class="pl-pds">'</span>Acceleration Z: <span class="pl-pds">'</span></span> <span class="pl-k">+</span> acceleration.z <span class="pl-k">+</span> <span class="pl-s"><span class="pl-pds">'</span><span class="pl-cce">\n</span><span class="pl-pds">'</span></span> <span class="pl-k">+</span>
<span class="pl-s"><span class="pl-pds">'</span>Timestamp: <span class="pl-pds">'</span></span> <span class="pl-k">+</span> acceleration.timestamp <span class="pl-k">+</span> <span class="pl-s"><span class="pl-pds">'</span><span class="pl-cce">\n</span><span class="pl-pds">'</span></span>);
};</pre></div>
<ul>
<li>停止获取加速计状态(不需要加速计状态时,务必调用来停止加速计刷新)</li>
</ul>
<div class="highlight highlight-javascript"><pre><span class="pl-k">var</span> params <span class="pl-k">=</span> { <span class="pl-s"><span class="pl-pds">"</span>Native_Motion<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-s"><span class="pl-pds">"</span>clearWatchAcceleration<span class="pl-pds">"</span></span> };</pre></div>
<h5>
<a id="user-content-6-filesystem" class="anchor" href="#6-filesystem" aria-hidden="true"><span class="octicon octicon-link"></span></a>6. FileSystem</h5>
<ul>
<li>获取目录</li>
</ul>
<div class="highlight highlight-javascript"><pre><span class="pl-c">&lt;!--</span> Documents目录 <span class="pl-c">--&gt;</span>
<span class="pl-k">var</span> params <span class="pl-k">=</span> { <span class="pl-s"><span class="pl-pds">"</span>Native_FS<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-s"><span class="pl-pds">"</span>getDocumentsPath<span class="pl-pds">"</span></span> };
<span class="pl-c">&lt;!--</span> tmp目录 <span class="pl-c">--&gt;</span>
<span class="pl-k">var</span> params <span class="pl-k">=</span> { <span class="pl-s"><span class="pl-pds">"</span>Native_FS<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-s"><span class="pl-pds">"</span>getTemporaryPath<span class="pl-pds">"</span></span> };
<span class="pl-c">&lt;!--</span> cache目录 <span class="pl-c">--&gt;</span>
<span class="pl-k">var</span> params <span class="pl-k">=</span> { <span class="pl-s"><span class="pl-pds">"</span>Native_FS<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-s"><span class="pl-pds">"</span>getCachePath<span class="pl-pds">"</span></span> };
<span class="pl-c">&lt;!--</span> 回调Example<span class="pl-k">:</span> <span class="pl-c">--&gt;</span>
<span class="pl-k">function</span> <span class="pl-en">onSuccess</span>(<span class="pl-smi">path</span>) {
<span class="pl-c1">alert</span>(<span class="pl-s"><span class="pl-pds">'</span>path: <span class="pl-pds">'</span></span> <span class="pl-k">+</span> path);
};</pre></div>
<ul>
<li>删除文件</li>
</ul>
<div class="highlight highlight-javascript"><pre><span class="pl-k">var</span> params <span class="pl-k">=</span> { <span class="pl-s"><span class="pl-pds">"</span>Native_FS<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-s"><span class="pl-pds">"</span>deleteItemAtPath<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>options<span class="pl-pds">"</span></span><span class="pl-k">:</span>{ <span class="pl-s"><span class="pl-pds">"</span>path<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-s"><span class="pl-pds">"</span>itemPath<span class="pl-pds">"</span></span> } };</pre></div>
<ul>
<li>拷贝文件</li>
</ul>
<div class="highlight highlight-javascript"><pre><span class="pl-k">var</span> params <span class="pl-k">=</span> { <span class="pl-s"><span class="pl-pds">"</span>Native_FS<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-s"><span class="pl-pds">"</span>copyItem<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>options<span class="pl-pds">"</span></span><span class="pl-k">:</span>{ <span class="pl-s"><span class="pl-pds">"</span>srcPath<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-s"><span class="pl-pds">"</span>xxx<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>dstPath<span class="pl-pds">"</span></span><span class="pl-k">:</span><span class="pl-s"><span class="pl-pds">"</span>xxx<span class="pl-pds">"</span></span> } };</pre></div>
</article></body></html>
\ No newline at end of file
... ...
### 基本使用
```javascript
<!-- 组装参数,下面是基本参数结构 -->
var params = { "ability":"action", "options":{"optionKey":"optionValue"} };
<!-- 触发机能 -->
yohoInterface.triggerEvent(onSuccess, onFail, params);
```
`onSuccess`回调里面会传递结果。
###具体定义
##### 1. 摄像头
* 拍照/访问相册
```javascript
<!--
quality(照片质量) 0-100
pictureSourceType(照片源): 1. 访问相册 SAVEDPHOTOALBUM 2. 摄像头 CAMERA
targetSize(照片尺寸,单位:像素): 如果其中某个设为0,则认为等比缩放
-->
var params = { "Native_Camera":"takePicture", "options":{ "quality":75, "pictureSourceType":"CAMERA", "targetSize":{ "width":100, "height":100 } } };
```
* 展示获取的照片Example
```javascript
function onSuccess(imageData) {
var image = document.getElementById('myImage');
image.src = "data:image/jpeg;base64," + imageData;
}
```
##### 2. LBS
* 获取Location
```javascript
var params = { "Native_LBS":"getLocation" };
<!-- 回调Example: -->
function onSuccess(coordinate) {
alert('Coordinate Latitude: ' + coordinate.latitude + '\n' +
'Coordinate Longitude: ' + coordinate.longitude);
};
```
* 获取所在地理位置信息
```javascript
var params = { "Native_LBS":"getLocationDetail" };
<!-- 回调Example:
国家 - placemark.country
国家代号 - placemark.countryCode
城市 - placemark.city
- placemark.state
街道 - placemark.street
- placemark.sublocality
完整地址名称 - placemark.name
-->
function onSuccess(placemark) {
alert('name: ' + placemark.name + '\n' +
'countryCode: ' + placemark.countryCode + '\n' +
'country: ' + placemark.country + '\n' +
'state: ' + placemark.state + '\n' +
'city: ' + placemark.city + '\n' +
'sublocality: ' + placemark.sublocality + '\n' +
'street: ' + placemark.street);
};
```
##### 3. Device
* 获取设备信息
```javascript
var params = { "Native_Device":"getDeviceInfo" };
<!-- 回调Example: -->
function onSuccess(device) {
alert('Model: ' + device.model + '\n' +
'Platform: ' + device.platform + '\n' +
'OSVersion: ' + device.version);
};
```
##### 4. Media
* 调用iOS媒体播放器
```javascript
var params = { "Native_Media":"playMedia", "options":{ "url":"http://xxxxxxx.mp4" } };
```
##### 5. 传感器
* 震动
```javascript
<!-- duration为震动时长 -->
var params = { "Native_Motion":"vibrate", "options":{ "duration":1.2 } };
```
* 获取加速计状态
```javascript
<!-- period为观察间隔,单位是毫秒 -->
var params = { "Native_Motion":"watchAcceleration", "options":{ "period":1000 } };
<!-- 回调Example: -->
function onSuccess(acceleration) {
alert('Acceleration X: ' + acceleration.x + '\n' +
'Acceleration Y: ' + acceleration.y + '\n' +
'Acceleration Z: ' + acceleration.z + '\n' +
'Timestamp: ' + acceleration.timestamp + '\n');
};
```
* 停止获取加速计状态(不需要加速计状态时,务必调用来停止加速计刷新)
```javascript
var params = { "Native_Motion":"clearWatchAcceleration" };
```
##### 6. FileSystem
* 获取目录
```javascript
<!-- Documents目录 -->
var params = { "Native_FS":"getDocumentsPath" };
<!-- tmp目录 -->
var params = { "Native_FS":"getTemporaryPath" };
<!-- cache目录 -->
var params = { "Native_FS":"getCachePath" };
<!-- 回调Example: -->
function onSuccess(path) {
alert('path: ' + path);
};
```
* 删除文件
```javascript
var params = { "Native_FS":"deleteItemAtPath", "options":{ "path":"itemPath" } };
```
* 拷贝文件
```javascript
var params = { "Native_FS":"copyItem", "options":{ "srcPath":"xxx", "dstPath":"xxx" } };
```
... ...
//
// YHURLCache.h
// YohoExplorerDemo
//
// Created by gaoqiang xu on 4/16/15.
// Copyright (c) 2015 gaoqiang xu. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface YHURLCache : NSURLCache
- (instancetype)initWithMemoryCapacity:(NSUInteger)memoryCapacity
diskCapacity:(NSUInteger)diskCapacity
diskPath:(NSString *)path
cacheDuration:(NSInteger)cacheDuration;
- (void)addCacheUrl:(NSString *)url forKey:(id)object;
- (void)removeUrlsForKey:(id)object;
@end
... ...
//
// YHURLCache.m
// YohoExplorerDemo
//
// Created by gaoqiang xu on 4/16/15.
// Copyright (c) 2015 gaoqiang xu. All rights reserved.
//
#import "YHURLCache.h"
#import <CommonCrypto/CommonDigest.h>
@interface YHURLCache ()
@property (copy, atomic) NSString *diskPath;
@property (atomic) NSInteger cacheDuration;
@property (strong, atomic) NSCache *memCache;
@property (strong, nonatomic) NSArray *cacheTypes;
@property (strong, nonatomic) NSMutableDictionary *webViewCacheUrls;
@end
@implementation YHURLCache
#pragma mark - Override
- (void)dealloc
{
[self.memCache removeAllObjects];
}
- (NSArray *)cacheTypes
{
if (!_cacheTypes) {
_cacheTypes = @[ @"jpg", @"jpeg", @"png", @"gif", @"html", @"css" ].mutableCopy;
}
return _cacheTypes;
}
- (instancetype)initWithMemoryCapacity:(NSUInteger)memoryCapacity
diskCapacity:(NSUInteger)diskCapacity
diskPath:(NSString *)path
cacheDuration:(NSInteger)cacheDuration
{
self = [self initWithMemoryCapacity:memoryCapacity diskCapacity:diskCapacity diskPath:path];
if (self) {
_cacheDuration = cacheDuration;
}
return self;
}
- (instancetype)initWithMemoryCapacity:(NSUInteger)memoryCapacity diskCapacity:(NSUInteger)diskCapacity diskPath:(NSString *)path
{
self = [super initWithMemoryCapacity:memoryCapacity diskCapacity:diskCapacity diskPath:path];
if (self) {
if (path) {
_diskPath = path;
} else {
_diskPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
}
_memCache = [[NSCache alloc] init];
_cacheDuration = 0;
}
return self;
}
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request
{
if (request.cachePolicy == NSURLCacheStorageNotAllowed || [request.URL.absoluteString hasPrefix:@"file://"] || [request.URL.absoluteString hasPrefix:@"data:"]) {
return nil;
}
NSString *url = [self removeParams:request.URL.absoluteString];
NSString *extension = [[url pathExtension] lowercaseString];
NSArray *types = [self.cacheTypes filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF = %@", extension]];
if ([request.HTTPMethod isEqualToString:@"GET"]
&& (types.count == 1 || [self existInCacheDictionary:request] )) {
return [self cachedDataForRequest:request];
} else {
return [super cachedResponseForRequest:request];
}
}
- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse forRequest:(NSURLRequest *)request
{
NSString *url = [self removeParams:request.URL.absoluteString];
NSString *extension = [[url pathExtension] lowercaseString];
NSArray *types = [self.cacheTypes filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF = %@", extension]];
if ([request.HTTPMethod isEqualToString:@"GET"]
&& (types.count == 1 || [self existInCacheDictionary:request] )) {
NSHTTPURLResponse *response = (NSHTTPURLResponse *)cachedResponse.response;
if (cachedResponse.response && cachedResponse.data && [response statusCode] == 200) {
NSDate *date = [NSDate date];
NSString *url = request.URL.absoluteString;
NSString *urlWithOtherInfo = [[NSString alloc] initWithFormat:@"%@-otherInfo", url];
NSString *filePath = [self cacheFilePath:[self md5Hash:url]];
NSString *otherInfoPath = [self cacheFilePath:[self md5Hash:urlWithOtherInfo]];
NSDictionary *dic;
if (cachedResponse.response.textEncodingName) {
dic = @{ @"time":[NSString stringWithFormat:@"%.0f", [date timeIntervalSince1970]],
@"MIMEType":cachedResponse.response.MIMEType,
@"textEncodingName":cachedResponse.response.textEncodingName };
} else {
dic = @{ @"time":[NSString stringWithFormat:@"%.0f", [date timeIntervalSince1970]],
@"MIMEType":cachedResponse.response.MIMEType };
}
[self.memCache setObject:cachedResponse.data forKey:[filePath lastPathComponent]];
[self.memCache setObject:dic forKey:[otherInfoPath lastPathComponent]];
[dic writeToFile:otherInfoPath atomically:YES];
[cachedResponse.data writeToFile:filePath atomically:YES];
}
} else {
[super storeCachedResponse:cachedResponse forRequest:request];
}
}
- (void)removeAllCachedResponses
{
[super removeAllCachedResponses];
[self deleteCacheFolder];
[self.memCache removeAllObjects];
}
- (void)removeCachedResponseForRequest:(NSURLRequest *)request
{
[super removeCachedResponseForRequest:request];
NSString *url = request.URL.absoluteString;
NSString *urlWithOtherInfo = [[NSString alloc] initWithFormat:@"%@-otherInfo", url];
NSString *filePath = [self cacheFilePath:[self md5Hash:url]];
NSString *otherInfoPath = [self cacheFilePath:[self md5Hash:urlWithOtherInfo]];
[self.memCache removeObjectForKey:[filePath lastPathComponent]];
[self.memCache removeObjectForKey:[otherInfoPath lastPathComponent]];
NSFileManager *fm = [[NSFileManager alloc] init];
[fm removeItemAtPath:filePath error:nil];
[fm removeItemAtPath:otherInfoPath error:nil];
}
#pragma mark - Setter & Getter
- (NSMutableDictionary *)webViewCacheUrls
{
if (!_webViewCacheUrls) {
_webViewCacheUrls = @{}.mutableCopy;
}
return _webViewCacheUrls;
}
#pragma mark - Private
- (NSString *)removeParams:(NSString *)url
{
NSString *freshUrl = url;
NSRange rangeQ = [url rangeOfString:@"?"];
if (rangeQ.location != NSNotFound) {
freshUrl = [url substringToIndex:rangeQ.location];
}
return freshUrl;
}
- (BOOL)existInCacheDictionary:(NSURLRequest *)request
{
BOOL existCacheUrl = NO;
for (id object in [self.webViewCacheUrls allKeys]) {
NSArray *temp = self.webViewCacheUrls[object];
for (NSString *url in temp) {
if ([url isEqualToString:request.URL.absoluteString]) {
existCacheUrl = YES;
break;
}
}
if (existCacheUrl) {
break;
}
}
return existCacheUrl;
}
- (NSString *)md5Hash:(NSString *)str
{
const char *cStr = [str UTF8String];
unsigned char result[16];
CC_MD5(cStr, (unsigned int)strlen(cStr), result);
NSString *md5Result = [NSString stringWithFormat:
@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
result[0], result[1], result[2], result[3],
result[4], result[5], result[6], result[7],
result[8], result[9], result[10], result[11],
result[12], result[13], result[14], result[15]
];
return md5Result;
}
- (NSString *)cacheFolder
{
return @"yh_url_cache";
}
- (void)deleteCacheFolder
{
NSString *path = [NSString stringWithFormat:@"%@/%@", self.diskPath, [self cacheFolder]];
NSFileManager *fileManager = [[NSFileManager alloc] init];
[fileManager removeItemAtPath:path error:nil];
}
- (NSString *)cacheFilePath:(NSString *)fileName
{
NSString *path = [[NSString alloc] initWithFormat:@"%@/%@", self.diskPath, self.cacheFolder];
NSFileManager *fm = [[NSFileManager alloc] init];
BOOL isDir;
if ([fm fileExistsAtPath:path isDirectory:&isDir] && isDir) {
} else {
[fm createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
}
return [path stringByAppendingPathComponent:fileName];
}
- (NSCachedURLResponse *)cachedDataForRequest:(NSURLRequest *)request
{
NSString *url = request.URL.absoluteString;
NSString *urlWithOtherInfo = [[NSString alloc] initWithFormat:@"%@-otherInfo", url];
NSString *filePath = [self cacheFilePath:[self md5Hash:url]];
NSString *otherInfoPath = [self cacheFilePath:[self md5Hash:urlWithOtherInfo]];
NSDate *date = [NSDate date];
NSFileManager *fm = [[NSFileManager alloc] init];
if ([fm fileExistsAtPath:filePath]) {
BOOL expire = NO;
NSDictionary *otherInfo = [self.memCache objectForKey:[otherInfoPath lastPathComponent]];
if (!otherInfo) {
otherInfo = [[NSDictionary alloc] initWithContentsOfFile:otherInfoPath];
if (otherInfo) {
[self.memCache setObject:otherInfo forKey:[otherInfoPath lastPathComponent]];
}
}
if (self.cacheDuration > 0) {
NSInteger createTime = [otherInfo[@"time"] integerValue];
if (createTime + self.cacheDuration < date.timeIntervalSince1970) {
expire = YES;
}
}
if (!expire) {
// Getting data from cache
NSData *data = [self.memCache objectForKey:[filePath lastPathComponent]];
if (!data) {
data = [[NSData alloc] initWithContentsOfFile:filePath];
if (data) {
[self.memCache setObject:data forKey:[filePath lastPathComponent]];
}
}
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:request.URL
MIMEType:otherInfo[@"MIMEType"]
expectedContentLength:data.length
textEncodingName:otherInfo[@"textEncodingName"]];
NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data];
return cachedResponse;
} else {
// Removing old data
[fm removeItemAtPath:filePath error:nil];
[fm removeItemAtPath:otherInfoPath error:nil];
[self.memCache removeObjectForKey:[filePath lastPathComponent]];
[self.memCache removeObjectForKey:[otherInfoPath lastPathComponent]];
}
}
return nil;
}
#pragma mark - Public
- (void)addCacheUrl:(NSString *)url forKey:(id)object
{
NSMutableArray *array = self.webViewCacheUrls[object];
if (!array) {
array = @[].mutableCopy;
self.webViewCacheUrls[object] = array;
}
if (array.count == 0
|| [array filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF = %@", url]].count == 0) {
[array addObject:url];
}
}
- (void)removeUrlsForKey:(id)object
{
[self.webViewCacheUrls removeObjectForKey:object];
}
@end
... ...
//
// YH_WebURLCache.h
// YH_Mall
//
// Created by Christ on 15/7/17.
// Copyright (c) 2015年 YOHO. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface YH_WebURLCache : NSURLCache
+ (instancetype)shareURLCache;
- (void)clearCacheWithRequestUrl:(NSString *)requestUrl;
- (void)saveCacheRequestDictWith:(NSString *)updateFlag requestUrl:(NSString *)requesetUrl;
- (void)refreshWebViewCacheWithUpdateFlag:(NSString *)updateFlag requestUrl:(NSString *)requestUrl;
@end
... ...
//
// YH_WebURLCache.m
// YH_Mall
//
// Created by Christ on 15/7/17.
// Copyright (c) 2015年 YOHO. All rights reserved.
//
#import "YH_WebURLCache.h"
#import "NSString+Sha1.h"
#import "YH_WebURLProtocol.h"
@interface YH_WebURLCache ()
@property (strong, nonatomic) NSArray *htmlURLCachePrefixes;
@property (strong, nonatomic) NSArray *urlCacheSupportMimes;
@end
@implementation YH_WebURLCache
+ (instancetype)shareURLCache
{
static YH_WebURLCache *webUrlCache = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
webUrlCache = [[YH_WebURLCache alloc] initWithMemoryCapacity:1024*1024*5 diskCapacity:1024*1024*20 diskPath:nil];
});
return webUrlCache;
}
- (instancetype)initWithMemoryCapacity:(NSUInteger)memoryCapacity diskCapacity:(NSUInteger)diskCapacity diskPath:(NSString *)path
{
self = [super initWithMemoryCapacity:memoryCapacity diskCapacity:diskCapacity diskPath:path];
if (self) {
self.htmlURLCachePrefixes = @[@"http://guang.m.yohobuy.com",
@"http://feature.yohobuy.com",
@"http://121.40.138.49/yushui1/H5/ai1",
@"http://file.static.yhbimg.com"];
self.urlCacheSupportMimes = @[@"image/jpg", @"image/jpeg", @"image/png", @"image/gif", @"application/javascript",@"application/x-javascript", @"text/css",@"text/html"];
}
return self;
}
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request
{
NSCachedURLResponse *response = [super cachedResponseForRequest:request];
return response;
}
- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse forRequest:(NSURLRequest *)request
{
[super storeCachedResponse:cachedResponse forRequest:request];
YH_CachedURLResponse *localCachedURLReponse = [YH_CachedURLResponse cachedResponseWith:cachedResponse];
NSString *cachePath = [YH_WebURLProtocol cachePathForRequest:request];
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)cachedResponse.response;
//缓存的条件是http request 并且状态码在200内
if ([httpResponse isKindOfClass:[NSHTTPURLResponse class]]) {
if (httpResponse.statusCode >= 200 && httpResponse.statusCode <300) {
NSString *mimeType = cachedResponse.response.MIMEType;
NSArray *supportMimeArr = self.urlCacheSupportMimes;
if ([mimeType isEqualToString:@"text/html"]){
if ([self shouldCacheHtmlWithURL:httpResponse.URL.absoluteString]) {
[NSKeyedArchiver archiveRootObject:localCachedURLReponse toFile:cachePath];
[[YH_GlobalDataCenter defaultCenter] checkClearCacheResponseData];
}
}
else if (![mimeType isEqualToString:@"application/json"]) {
[NSKeyedArchiver archiveRootObject:localCachedURLReponse toFile:cachePath];
[[YH_GlobalDataCenter defaultCenter] checkClearCacheResponseData];
}
}
}
}
#pragma mark - Other Methods
//指定的域名前缀链接会被缓存
- (BOOL)shouldCacheHtmlWithURL:(NSString *)htmlURL
{
BOOL shouldCache = NO;
for (NSString *httpPrefix in self.htmlURLCachePrefixes) {
if ([htmlURL hasPrefix:httpPrefix]) {
return YES;
}
}
return shouldCache;
}
- (void)refreshWebViewCacheWithUpdateFlag:(NSString *)updateFlag requestUrl:(NSString *)requestUrl
{
BOOL shouldLoadCache = [self shouldLoadCacheRequestWith:updateFlag requestUrl:requestUrl];
if (!shouldLoadCache) {
[self clearCacheWithRequestUrl:requestUrl];
}
}
- (BOOL)shouldLoadCacheRequestWith:(NSString *)updateFlag requestUrl:(NSString *)requesetUrl
{
if (updateFlag.length*requesetUrl.length == 0) {
return NO;
}
NSString *md5 = [requesetUrl sha1];
NSString *legacyUpdateFlag = [[YH_GlobalDataCenter defaultCenter].requestCacheDict stringForKey:md5];
if ([legacyUpdateFlag isEqualToString:updateFlag]) {
return YES;
} else {
return NO;
}
}
- (void)saveCacheRequestDictWith:(NSString *)updateFlag requestUrl:(NSString *)requesetUrl
{
if (updateFlag.length*requesetUrl.length == 0) {
return;
}
NSString *md5 = [requesetUrl sha1];
[[YH_GlobalDataCenter defaultCenter] saveCacheRequestWithUpdateFlag:updateFlag forUrlMd5:md5];
}
- (void)clearCacheWithRequestUrl:(NSString *)requestUrl
{
NSString *filePath = [self cachePathForRequestUrl:requestUrl];
if (filePath.length>0) {
NSError *error = nil;
[[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
}
}
- (NSString *)cachePathForRequestUrl:(NSString *)requestUrl
{
// This stores in the Caches directory, which can be deleted when space is low, but we only use it for offline access
requestUrl = [requestUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *cachesPath = kPathWebViewCache;
NSString *fileName = [requestUrl sha1];
return [cachesPath stringByAppendingPathComponent:fileName];
}
@end
... ...
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import <Foundation/Foundation.h>
@class CDVInvokedUrlCommand;
@class CDVViewController;
@interface CDVCommandQueue : NSObject
@property (nonatomic, readonly) BOOL currentlyExecuting;
- (id)initWithViewController:(CDVViewController*)viewController;
- (void)dispose;
- (void)resetRequestId;
- (void)enqueueCommandBatch:(NSString*)batchJSON;
- (void)processXhrExecBridgePoke:(NSNumber*)requestId;
- (void)fetchCommandsFromJs;
- (void)executePending;
- (BOOL)execute:(CDVInvokedUrlCommand*)command;
@end
... ...
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#include <objc/message.h>
#import "CDV.h"
#import "CDVCommandQueue.h"
#import "CDVViewController.h"
#import "CDVCommandDelegateImpl.h"
#import "CDVJSON_private.h"
// Parse JS on the main thread if it's shorter than this.
static const NSInteger JSON_SIZE_FOR_MAIN_THREAD = 4 * 1024; // Chosen arbitrarily.
// Execute multiple commands in one go until this many seconds have passed.
static const double MAX_EXECUTION_TIME = .008; // Half of a 60fps frame.
@interface CDVCommandQueue () {
NSInteger _lastCommandQueueFlushRequestId;
__weak CDVViewController* _viewController;
NSMutableArray* _queue;
NSTimeInterval _startExecutionTime;
}
@end
@implementation CDVCommandQueue
- (BOOL)currentlyExecuting
{
return _startExecutionTime > 0;
}
- (id)initWithViewController:(CDVViewController*)viewController
{
self = [super init];
if (self != nil) {
_viewController = viewController;
_queue = [[NSMutableArray alloc] init];
}
return self;
}
- (void)dispose
{
// TODO(agrieve): Make this a zeroing weak ref once we drop support for 4.3.
_viewController = nil;
}
- (void)resetRequestId
{
_lastCommandQueueFlushRequestId = 0;
}
- (void)enqueueCommandBatch:(NSString*)batchJSON
{
if ([batchJSON length] > 0) {
NSMutableArray* commandBatchHolder = [[NSMutableArray alloc] init];
[_queue addObject:commandBatchHolder];
if ([batchJSON length] < JSON_SIZE_FOR_MAIN_THREAD) {
[commandBatchHolder addObject:[batchJSON cdv_JSONObject]];
} else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^() {
NSMutableArray* result = [batchJSON cdv_JSONObject];
@synchronized(commandBatchHolder) {
[commandBatchHolder addObject:result];
}
[self performSelectorOnMainThread:@selector(executePending) withObject:nil waitUntilDone:NO];
});
}
}
}
- (void)processXhrExecBridgePoke:(NSNumber*)requestId
{
NSInteger rid = [requestId integerValue];
// An ID of 1 is a special case because that signifies the first request of
// the page. Since resetRequestId is called from webViewDidStartLoad, and the
// JS context at the time of webViewDidStartLoad is still that of the previous
// page, it's possible for requests from the previous page to come in after this
// point. We ignore these by enforcing that ID=1 be the first ID.
if ((_lastCommandQueueFlushRequestId == 0) && (rid != 1)) {
CDV_EXEC_LOG(@"Exec: Ignoring exec request from previous page.");
return;
}
// Use the request ID to determine if we've already flushed for this request.
// This is required only because the NSURLProtocol enqueues the same request
// multiple times.
if (rid > _lastCommandQueueFlushRequestId) {
_lastCommandQueueFlushRequestId = [requestId integerValue];
[self fetchCommandsFromJs];
[self executePending];
}
}
- (void)fetchCommandsFromJs
{
// Grab all the queued commands from the JS side.
NSString* queuedCommandsJSON = [_viewController.webView stringByEvaluatingJavaScriptFromString:
@"cordova.require('cordova/exec').nativeFetchMessages()"];
CDV_EXEC_LOG(@"Exec: Flushed JS->native queue (hadCommands=%d).", [queuedCommandsJSON length] > 0);
[self enqueueCommandBatch:queuedCommandsJSON];
}
- (void)executePending
{
// Make us re-entrant-safe.
if (_startExecutionTime > 0) {
return;
}
@try {
_startExecutionTime = [NSDate timeIntervalSinceReferenceDate];
while ([_queue count] > 0) {
NSMutableArray* commandBatchHolder = _queue[0];
NSMutableArray* commandBatch = nil;
@synchronized(commandBatchHolder) {
// If the next-up command is still being decoded, wait for it.
if ([commandBatchHolder count] == 0) {
break;
}
commandBatch = commandBatchHolder[0];
}
while ([commandBatch count] > 0) {
@autoreleasepool {
// Execute the commands one-at-a-time.
NSArray* jsonEntry = [commandBatch dequeue];
if ([commandBatch count] == 0) {
[_queue removeObjectAtIndex:0];
}
CDVInvokedUrlCommand* command = [CDVInvokedUrlCommand commandFromJson:jsonEntry];
CDV_EXEC_LOG(@"Exec(%@): Calling %@.%@", command.callbackId, command.className, command.methodName);
if (![self execute:command]) {
#ifdef DEBUG
NSString* commandJson = [jsonEntry cdv_JSONString];
static NSUInteger maxLogLength = 1024;
NSString* commandString = ([commandJson length] > maxLogLength) ?
[NSString stringWithFormat:@"%@[...]", [commandJson substringToIndex:maxLogLength]] :
commandJson;
DLog(@"FAILED pluginJSON = %@", commandString);
#endif
}
}
// Yield if we're taking too long.
if (([_queue count] > 0) && ([NSDate timeIntervalSinceReferenceDate] - _startExecutionTime > MAX_EXECUTION_TIME)) {
[self performSelector:@selector(executePending) withObject:nil afterDelay:0];
return;
}
}
}
} @finally
{
_startExecutionTime = 0;
}
}
- (BOOL)execute:(CDVInvokedUrlCommand*)command
{
if ((command.className == nil) || (command.methodName == nil)) {
// NSLog(@"ERROR: Classname and/or methodName not found for command.");
return NO;
}
// Fetch an instance of this class
CDVPlugin* obj = [_viewController.commandDelegate getCommandInstance:command.className];
if (!([obj isKindOfClass:[CDVPlugin class]])) {
// NSLog(@"ERROR: Plugin '%@' not found, or is not a CDVPlugin. Check your plugin mapping in config.xml.", command.className);
return NO;
}
BOOL retVal = YES;
double started = [[NSDate date] timeIntervalSince1970] * 1000.0;
// Find the proper selector to call.
NSString* methodName = [NSString stringWithFormat:@"%@:", command.methodName];
SEL normalSelector = NSSelectorFromString(methodName);
if ([obj respondsToSelector:normalSelector]) {
// [obj performSelector:normalSelector withObject:command];
((void (*)(id, SEL, id))objc_msgSend)(obj, normalSelector, command);
} else {
// There's no method to call, so throw an error.
// NSLog(@"ERROR: Method '%@' not defined in Plugin '%@'", methodName, command.className);
retVal = NO;
}
double elapsed = [[NSDate date] timeIntervalSince1970] * 1000.0 - started;
if (elapsed > 10) {
// NSLog(@"THREAD WARNING: ['%@'] took '%f' ms. Plugin should use a background thread.", command.className, elapsed);
}
return retVal;
}
@end
... ...
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
@interface CDVConfigParser : NSObject <NSXMLParserDelegate>
{
NSString* featureName;
}
@property (nonatomic, readonly, strong) NSMutableDictionary* pluginsDict;
@property (nonatomic, readonly, strong) NSMutableDictionary* settings;
@property (nonatomic, readonly, strong) NSMutableArray* whitelistHosts;
@property (nonatomic, readonly, strong) NSMutableArray* startupPluginNames;
@property (nonatomic, readonly, strong) NSString* startPage;
@end
... ...
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import "CDVConfigParser.h"
@interface CDVConfigParser ()
@property (nonatomic, readwrite, strong) NSMutableDictionary* pluginsDict;
@property (nonatomic, readwrite, strong) NSMutableDictionary* settings;
@property (nonatomic, readwrite, strong) NSMutableArray* whitelistHosts;
@property (nonatomic, readwrite, strong) NSMutableArray* startupPluginNames;
@property (nonatomic, readwrite, strong) NSString* startPage;
@end
@implementation CDVConfigParser
@synthesize pluginsDict, settings, whitelistHosts, startPage, startupPluginNames;
- (id)init
{
self = [super init];
if (self != nil) {
self.pluginsDict = [[NSMutableDictionary alloc] initWithCapacity:30];
self.settings = [[NSMutableDictionary alloc] initWithCapacity:30];
self.whitelistHosts = [[NSMutableArray alloc] initWithCapacity:30];
[self.whitelistHosts addObject:@"file:///*"];
[self.whitelistHosts addObject:@"content:///*"];
[self.whitelistHosts addObject:@"data:///*"];
self.startupPluginNames = [[NSMutableArray alloc] initWithCapacity:8];
featureName = nil;
}
return self;
}
- (void)parser:(NSXMLParser*)parser didStartElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName attributes:(NSDictionary*)attributeDict
{
if ([elementName isEqualToString:@"preference"]) {
settings[[attributeDict[@"name"] lowercaseString]] = attributeDict[@"value"];
} else if ([elementName isEqualToString:@"feature"]) { // store feature name to use with correct parameter set
featureName = [attributeDict[@"name"] lowercaseString];
} else if ((featureName != nil) && [elementName isEqualToString:@"param"]) {
NSString* paramName = [attributeDict[@"name"] lowercaseString];
id value = attributeDict[@"value"];
if ([paramName isEqualToString:@"ios-package"]) {
pluginsDict[featureName] = value;
}
BOOL paramIsOnload = ([paramName isEqualToString:@"onload"] && [@"true" isEqualToString : value]);
BOOL attribIsOnload = [@"true" isEqualToString :[attributeDict[@"onload"] lowercaseString]];
if (paramIsOnload || attribIsOnload) {
[self.startupPluginNames addObject:featureName];
}
} else if ([elementName isEqualToString:@"access"]) {
[whitelistHosts addObject:attributeDict[@"origin"]];
} else if ([elementName isEqualToString:@"content"]) {
self.startPage = attributeDict[@"src"];
}
}
- (void)parser:(NSXMLParser*)parser didEndElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName
{
if ([elementName isEqualToString:@"feature"]) { // no longer handling a feature so release
featureName = nil;
}
}
- (void)parser:(NSXMLParser*)parser parseErrorOccurred:(NSError*)parseError
{
NSAssert(NO, @"config.xml parse error line %ld col %ld", (long)[parser lineNumber], (long)[parser columnNumber]);
}
@end
... ...
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import <UIKit/UIKit.h>
#import <Foundation/NSJSONSerialization.h>
#import "CDVAvailability.h"
#import "CDVInvokedUrlCommand.h"
#import "CDVCommandDelegate.h"
#import "CDVCommandQueue.h"
#import "CDVWhitelist.h"
#import "CDVScreenOrientationDelegate.h"
#import "CDVPlugin.h"
@interface CDVViewController : UIViewController <UIWebViewDelegate, CDVScreenOrientationDelegate>{
@protected
id <CDVCommandDelegate> _commandDelegate;
@protected
CDVCommandQueue* _commandQueue;
NSString* _userAgent;
}
@property (nonatomic, strong) IBOutlet UIWebView* webView;
@property (nonatomic, readonly, strong) NSMutableDictionary* pluginObjects;
@property (nonatomic, readonly, strong) NSDictionary* pluginsMap;
@property (nonatomic, readonly, strong) NSMutableDictionary* settings;
@property (nonatomic, readonly, strong) NSXMLParser* configParser;
@property (nonatomic, readonly, strong) CDVWhitelist* whitelist; // readonly for public
@property (nonatomic, readonly, assign) BOOL loadFromString;
@property (nonatomic, readwrite, copy) NSString* wwwFolderName;
@property (nonatomic, readwrite, copy) NSString* startPage;
@property (nonatomic, readonly, strong) CDVCommandQueue* commandQueue;
@property (nonatomic, readonly, strong) id <CDVCommandDelegate> commandDelegate;
/**
The complete user agent that Cordova will use when sending web requests.
*/
@property (nonatomic, readonly) NSString* userAgent;
/**
The base user agent data that Cordova will use to build its user agent. If this
property isn't set, Cordova will use the standard web view user agent as its
base.
*/
@property (nonatomic, readwrite, copy) NSString* baseUserAgent;
+ (NSDictionary*)getBundlePlist:(NSString*)plistName;
+ (NSString*)applicationDocumentsDirectory;
- (void)printMultitaskingInfo;
- (void)createGapView;
- (UIWebView*)newCordovaViewWithFrame:(CGRect)bounds;
- (void)javascriptAlert:(NSString*)text;
- (NSString*)appURLScheme;
- (NSArray*)parseInterfaceOrientations:(NSArray*)orientations;
- (BOOL)supportsOrientation:(UIInterfaceOrientation)orientation;
- (id)getCommandInstance:(NSString*)pluginName;
- (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className;
- (void)registerPlugin:(CDVPlugin*)plugin withPluginName:(NSString*)pluginName;
- (BOOL)URLisAllowed:(NSURL*)url;
- (void)processOpenUrl:(NSURL*)url;
@end
... ...
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import <objc/message.h>
#import "CDV.h"
#import "CDVCommandDelegateImpl.h"
#import "CDVConfigParser.h"
#import "CDVUserAgentUtil.h"
#import "CDVWebViewDelegate.h"
#import <AVFoundation/AVFoundation.h>
#import "CDVHandleOpenURL.h"
#define degreesToRadian(x) (M_PI * (x) / 180.0)
@interface CDVViewController () {
NSInteger _userAgentLockToken;
CDVWebViewDelegate* _webViewDelegate;
}
@property (nonatomic, readwrite, strong) NSXMLParser* configParser;
@property (nonatomic, readwrite, strong) NSMutableDictionary* settings;
@property (nonatomic, readwrite, strong) CDVWhitelist* whitelist;
@property (nonatomic, readwrite, strong) NSMutableDictionary* pluginObjects;
@property (nonatomic, readwrite, strong) NSArray* startupPluginNames;
@property (nonatomic, readwrite, strong) NSDictionary* pluginsMap;
@property (nonatomic, readwrite, strong) NSArray* supportedOrientations;
@property (nonatomic, readwrite, assign) BOOL loadFromString;
@property (readwrite, assign) BOOL initialized;
@property (atomic, strong) NSURL* openURL;
@end
@implementation CDVViewController
@synthesize webView, supportedOrientations;
@synthesize pluginObjects, pluginsMap, whitelist, startupPluginNames;
@synthesize configParser, settings, loadFromString;
@synthesize wwwFolderName, startPage, initialized, openURL, baseUserAgent;
@synthesize commandDelegate = _commandDelegate;
@synthesize commandQueue = _commandQueue;
- (void)__init
{
if ((self != nil) && !self.initialized) {
_commandQueue = [[CDVCommandQueue alloc] initWithViewController:self];
_commandDelegate = [[CDVCommandDelegateImpl alloc] initWithViewController:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppWillTerminate:)
name:UIApplicationWillTerminateNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppWillResignActive:)
name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppDidBecomeActive:)
name:UIApplicationDidBecomeActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppWillEnterForeground:)
name:UIApplicationWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onPageDidLoad:)
name:CDVPageDidLoadNotification object:nil];
// read from UISupportedInterfaceOrientations (or UISupportedInterfaceOrientations~iPad, if its iPad) from -Info.plist
self.supportedOrientations = [self parseInterfaceOrientations:
[[[NSBundle mainBundle] infoDictionary] objectForKey:@"UISupportedInterfaceOrientations"]];
[self printVersion];
[self printMultitaskingInfo];
[self printPlatformVersionWarning];
self.initialized = YES;
// load config.xml settings
[self loadSettings];
}
}
- (id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
[self __init];
return self;
}
- (id)initWithCoder:(NSCoder*)aDecoder
{
self = [super initWithCoder:aDecoder];
[self __init];
return self;
}
- (id)init
{
self = [super init];
[self __init];
return self;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)printVersion
{
// NSLog(@"Apache Cordova native platform version %@ is starting.", CDV_VERSION);
}
- (void)printPlatformVersionWarning
{
if (!IsAtLeastiOSVersion(@"6.0")) {
// NSLog(@"CRITICAL: For Cordova 3.5.0 and above, you will need to upgrade to at least iOS 6.0 or greater. Your current version of iOS is %@.",
// [[UIDevice currentDevice] systemVersion]
// );
}
}
- (void)printMultitaskingInfo
{
UIDevice* device = [UIDevice currentDevice];
BOOL backgroundSupported = NO;
if ([device respondsToSelector:@selector(isMultitaskingSupported)]) {
backgroundSupported = device.multitaskingSupported;
}
NSNumber* exitsOnSuspend = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIApplicationExitsOnSuspend"];
if (exitsOnSuspend == nil) { // if it's missing, it should be NO (i.e. multi-tasking on by default)
exitsOnSuspend = [NSNumber numberWithBool:NO];
}
// NSLog(@"Multi-tasking -> Device: %@, App: %@", (backgroundSupported ? @"YES" : @"NO"), (![exitsOnSuspend intValue]) ? @"YES" : @"NO");
}
- (BOOL)URLisAllowed:(NSURL*)url
{
if (self.whitelist == nil) {
return YES;
}
return [self.whitelist URLIsAllowed:url];
}
- (void)loadSettings
{
CDVConfigParser* delegate = [[CDVConfigParser alloc] init];
// read from config.xml in the app bundle
NSString* path = [[NSBundle mainBundle] pathForResource:@"config" ofType:@"xml"];
if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
NSAssert(NO, @"ERROR: config.xml does not exist. Please run cordova-ios/bin/cordova_plist_to_config_xml path/to/project.");
return;
}
NSURL* url = [NSURL fileURLWithPath:path];
configParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
if (configParser == nil) {
// NSLog(@"Failed to initialize XML parser.");
return;
}
[configParser setDelegate:((id < NSXMLParserDelegate >)delegate)];
[configParser parse];
// Get the plugin dictionary, whitelist and settings from the delegate.
self.pluginsMap = delegate.pluginsDict;
self.startupPluginNames = delegate.startupPluginNames;
self.whitelist = [[CDVWhitelist alloc] initWithArray:delegate.whitelistHosts];
self.settings = delegate.settings;
// And the start folder/page.
self.wwwFolderName = @"www";
self.startPage = delegate.startPage;
if (self.startPage == nil) {
self.startPage = @"index.html";
}
// Initialize the plugin objects dict.
self.pluginObjects = [[NSMutableDictionary alloc] initWithCapacity:20];
}
- (NSURL*)appUrl
{
NSURL* appURL = nil;
if ([self.startPage rangeOfString:@"://"].location != NSNotFound) {
appURL = [NSURL URLWithString:self.startPage];
} else if ([self.wwwFolderName rangeOfString:@"://"].location != NSNotFound) {
appURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@/%@", self.wwwFolderName, self.startPage]];
} else {
// CB-3005 strip parameters from start page to check if page exists in resources
NSURL* startURL = [NSURL URLWithString:self.startPage];
NSString* startFilePath = [self.commandDelegate pathForResource:[startURL path]];
if (startFilePath == nil) {
self.loadFromString = YES;
appURL = nil;
} else {
appURL = [NSURL fileURLWithPath:startFilePath];
// CB-3005 Add on the query params or fragment.
NSString* startPageNoParentDirs = self.startPage;
NSRange r = [startPageNoParentDirs rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"?#"] options:0];
if (r.location != NSNotFound) {
NSString* queryAndOrFragment = [self.startPage substringFromIndex:r.location];
appURL = [NSURL URLWithString:queryAndOrFragment relativeToURL:appURL];
}
}
}
return appURL;
}
- (NSURL*)errorUrl
{
NSURL* errorURL = nil;
id setting = [self settingForKey:@"ErrorUrl"];
if (setting) {
NSString* errorUrlString = (NSString*)setting;
if ([errorUrlString rangeOfString:@"://"].location != NSNotFound) {
errorURL = [NSURL URLWithString:errorUrlString];
} else {
NSURL* url = [NSURL URLWithString:(NSString*)setting];
NSString* errorFilePath = [self.commandDelegate pathForResource:[url path]];
if (errorFilePath) {
errorURL = [NSURL fileURLWithPath:errorFilePath];
}
}
}
return errorURL;
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
// // Fix the iOS 5.1 SECURITY_ERR bug (CB-347), this must be before the webView is instantiated ////
NSString* backupWebStorageType = @"cloud"; // default value
id backupWebStorage = [self settingForKey:@"BackupWebStorage"];
if ([backupWebStorage isKindOfClass:[NSString class]]) {
backupWebStorageType = backupWebStorage;
}
[self setSetting:backupWebStorageType forKey:@"BackupWebStorage"];
if (IsAtLeastiOSVersion(@"5.1")) {
[CDVLocalStorage __fixupDatabaseLocationsWithBackupType:backupWebStorageType];
}
// // Instantiate the WebView ///////////////
if (!self.webView) {
[self createGapView];
}
// Configure WebView
_webViewDelegate = [[CDVWebViewDelegate alloc] initWithDelegate:self];
self.webView.delegate = _webViewDelegate;
// register this viewcontroller with the NSURLProtocol, only after the User-Agent is set
[CDVURLProtocol registerViewController:self];
// /////////////////
NSString* enableViewportScale = [self settingForKey:@"EnableViewportScale"];
NSNumber* allowInlineMediaPlayback = [self settingForKey:@"AllowInlineMediaPlayback"];
BOOL mediaPlaybackRequiresUserAction = YES; // default value
if ([self settingForKey:@"MediaPlaybackRequiresUserAction"]) {
mediaPlaybackRequiresUserAction = [(NSNumber*)[self settingForKey:@"MediaPlaybackRequiresUserAction"] boolValue];
}
self.webView.scalesPageToFit = [enableViewportScale boolValue];
/*
* Fire up CDVLocalStorage to work-around WebKit storage limitations: on all iOS 5.1+ versions for local-only backups, but only needed on iOS 5.1 for cloud backup.
*/
if (IsAtLeastiOSVersion(@"5.1") && (([backupWebStorageType isEqualToString:@"local"]) ||
([backupWebStorageType isEqualToString:@"cloud"] && !IsAtLeastiOSVersion(@"6.0")))) {
[self registerPlugin:[[CDVLocalStorage alloc] initWithWebView:self.webView] withClassName:NSStringFromClass([CDVLocalStorage class])];
}
/*
* This is for iOS 4.x, where you can allow inline <video> and <audio>, and also autoplay them
*/
if ([allowInlineMediaPlayback boolValue] && [self.webView respondsToSelector:@selector(allowsInlineMediaPlayback)]) {
self.webView.allowsInlineMediaPlayback = YES;
}
if ((mediaPlaybackRequiresUserAction == NO) && [self.webView respondsToSelector:@selector(mediaPlaybackRequiresUserAction)]) {
self.webView.mediaPlaybackRequiresUserAction = NO;
}
// By default, overscroll bouncing is allowed.
// UIWebViewBounce has been renamed to DisallowOverscroll, but both are checked.
BOOL bounceAllowed = YES;
NSNumber* disallowOverscroll = [self settingForKey:@"DisallowOverscroll"];
if (disallowOverscroll == nil) {
NSNumber* bouncePreference = [self settingForKey:@"UIWebViewBounce"];
bounceAllowed = (bouncePreference == nil || [bouncePreference boolValue]);
} else {
bounceAllowed = ![disallowOverscroll boolValue];
}
// prevent webView from bouncing
// based on the DisallowOverscroll/UIWebViewBounce key in config.xml
if (!bounceAllowed) {
if ([self.webView respondsToSelector:@selector(scrollView)]) {
((UIScrollView*)[self.webView scrollView]).bounces = NO;
} else {
for (id subview in self.webView.subviews) {
if ([[subview class] isSubclassOfClass:[UIScrollView class]]) {
((UIScrollView*)subview).bounces = NO;
}
}
}
}
NSString* decelerationSetting = [self settingForKey:@"UIWebViewDecelerationSpeed"];
if (![@"fast" isEqualToString:decelerationSetting]) {
[self.webView.scrollView setDecelerationRate:UIScrollViewDecelerationRateNormal];
}
/*
* iOS 6.0 UIWebView properties
*/
if (IsAtLeastiOSVersion(@"6.0")) {
BOOL keyboardDisplayRequiresUserAction = YES; // KeyboardDisplayRequiresUserAction - defaults to YES
if ([self settingForKey:@"KeyboardDisplayRequiresUserAction"] != nil) {
if ([self settingForKey:@"KeyboardDisplayRequiresUserAction"]) {
keyboardDisplayRequiresUserAction = [(NSNumber*)[self settingForKey:@"KeyboardDisplayRequiresUserAction"] boolValue];
}
}
// property check for compiling under iOS < 6
if ([self.webView respondsToSelector:@selector(setKeyboardDisplayRequiresUserAction:)]) {
[self.webView setValue:[NSNumber numberWithBool:keyboardDisplayRequiresUserAction] forKey:@"keyboardDisplayRequiresUserAction"];
}
BOOL suppressesIncrementalRendering = NO; // SuppressesIncrementalRendering - defaults to NO
if ([self settingForKey:@"SuppressesIncrementalRendering"] != nil) {
if ([self settingForKey:@"SuppressesIncrementalRendering"]) {
suppressesIncrementalRendering = [(NSNumber*)[self settingForKey:@"SuppressesIncrementalRendering"] boolValue];
}
}
// property check for compiling under iOS < 6
if ([self.webView respondsToSelector:@selector(setSuppressesIncrementalRendering:)]) {
[self.webView setValue:[NSNumber numberWithBool:suppressesIncrementalRendering] forKey:@"suppressesIncrementalRendering"];
}
}
/*
* iOS 7.0 UIWebView properties
*/
if (IsAtLeastiOSVersion(@"7.0")) {
SEL ios7sel = nil;
id prefObj = nil;
CGFloat gapBetweenPages = 0.0; // default
prefObj = [self settingForKey:@"GapBetweenPages"];
if (prefObj != nil) {
gapBetweenPages = [prefObj floatValue];
}
// property check for compiling under iOS < 7
ios7sel = NSSelectorFromString(@"setGapBetweenPages:");
if ([self.webView respondsToSelector:ios7sel]) {
[self.webView setValue:[NSNumber numberWithFloat:gapBetweenPages] forKey:@"gapBetweenPages"];
}
CGFloat pageLength = 0.0; // default
prefObj = [self settingForKey:@"PageLength"];
if (prefObj != nil) {
pageLength = [[self settingForKey:@"PageLength"] floatValue];
}
// property check for compiling under iOS < 7
ios7sel = NSSelectorFromString(@"setPageLength:");
if ([self.webView respondsToSelector:ios7sel]) {
[self.webView setValue:[NSNumber numberWithBool:pageLength] forKey:@"pageLength"];
}
NSInteger paginationBreakingMode = 0; // default - UIWebPaginationBreakingModePage
prefObj = [self settingForKey:@"PaginationBreakingMode"];
if (prefObj != nil) {
NSArray* validValues = @[@"page", @"column"];
NSString* prefValue = [validValues objectAtIndex:0];
if ([prefObj isKindOfClass:[NSString class]]) {
prefValue = prefObj;
}
paginationBreakingMode = [validValues indexOfObject:[prefValue lowercaseString]];
if (paginationBreakingMode == NSNotFound) {
paginationBreakingMode = 0;
}
}
// property check for compiling under iOS < 7
ios7sel = NSSelectorFromString(@"setPaginationBreakingMode:");
if ([self.webView respondsToSelector:ios7sel]) {
[self.webView setValue:[NSNumber numberWithInteger:paginationBreakingMode] forKey:@"paginationBreakingMode"];
}
NSInteger paginationMode = 0; // default - UIWebPaginationModeUnpaginated
prefObj = [self settingForKey:@"PaginationMode"];
if (prefObj != nil) {
NSArray* validValues = @[@"unpaginated", @"lefttoright", @"toptobottom", @"bottomtotop", @"righttoleft"];
NSString* prefValue = [validValues objectAtIndex:0];
if ([prefObj isKindOfClass:[NSString class]]) {
prefValue = prefObj;
}
paginationMode = [validValues indexOfObject:[prefValue lowercaseString]];
if (paginationMode == NSNotFound) {
paginationMode = 0;
}
}
// property check for compiling under iOS < 7
ios7sel = NSSelectorFromString(@"setPaginationMode:");
if ([self.webView respondsToSelector:ios7sel]) {
[self.webView setValue:[NSNumber numberWithInteger:paginationMode] forKey:@"paginationMode"];
}
}
if ([self.startupPluginNames count] > 0) {
[CDVTimer start:@"TotalPluginStartup"];
for (NSString* pluginName in self.startupPluginNames) {
[CDVTimer start:pluginName];
[self getCommandInstance:pluginName];
[CDVTimer stop:pluginName];
}
[CDVTimer stop:@"TotalPluginStartup"];
}
[self registerPlugin:[[CDVHandleOpenURL alloc] initWithWebView:self.webView] withClassName:NSStringFromClass([CDVHandleOpenURL class])];
// /////////////////
NSURL* appURL = [self appUrl];
[CDVUserAgentUtil acquireLock:^(NSInteger lockToken) {
self->_userAgentLockToken = lockToken;
[CDVUserAgentUtil setUserAgent:self.userAgent lockToken:lockToken];
if (appURL) {
NSURLRequest* appReq = [NSURLRequest requestWithURL:appURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
[self.webView loadRequest:appReq];
} else {}
}];
}
- (id)settingForKey:(NSString*)key
{
return [[self settings] objectForKey:[key lowercaseString]];
}
- (void)setSetting:(id)setting forKey:(NSString*)key
{
[[self settings] setObject:setting forKey:[key lowercaseString]];
}
- (NSArray*)parseInterfaceOrientations:(NSArray*)orientations
{
NSMutableArray* result = [[NSMutableArray alloc] init];
if (orientations != nil) {
NSEnumerator* enumerator = [orientations objectEnumerator];
NSString* orientationString;
while (orientationString = [enumerator nextObject]) {
if ([orientationString isEqualToString:@"UIInterfaceOrientationPortrait"]) {
[result addObject:[NSNumber numberWithInt:UIInterfaceOrientationPortrait]];
} else if ([orientationString isEqualToString:@"UIInterfaceOrientationPortraitUpsideDown"]) {
[result addObject:[NSNumber numberWithInt:UIInterfaceOrientationPortraitUpsideDown]];
} else if ([orientationString isEqualToString:@"UIInterfaceOrientationLandscapeLeft"]) {
[result addObject:[NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft]];
} else if ([orientationString isEqualToString:@"UIInterfaceOrientationLandscapeRight"]) {
[result addObject:[NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight]];
}
}
}
// default
if ([result count] == 0) {
[result addObject:[NSNumber numberWithInt:UIInterfaceOrientationPortrait]];
}
return result;
}
- (NSInteger)mapIosOrientationToJsOrientation:(UIInterfaceOrientation)orientation
{
switch (orientation) {
case UIInterfaceOrientationPortraitUpsideDown:
return 180;
case UIInterfaceOrientationLandscapeLeft:
return -90;
case UIInterfaceOrientationLandscapeRight:
return 90;
case UIInterfaceOrientationPortrait:
return 0;
default:
return 0;
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// First, ask the webview via JS if it supports the new orientation
NSString* jsCall = [NSString stringWithFormat:
@"window.shouldRotateToOrientation && window.shouldRotateToOrientation(%ld);"
, (long)[self mapIosOrientationToJsOrientation:interfaceOrientation]];
NSString* res = [webView stringByEvaluatingJavaScriptFromString:jsCall];
if ([res length] > 0) {
return [res boolValue];
}
// if js did not handle the new orientation (no return value), use values from the plist (via supportedOrientations)
return [self supportsOrientation:interfaceOrientation];
}
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
NSUInteger ret = 0;
if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortrait]) {
ret = ret | (1 << UIInterfaceOrientationPortrait);
}
if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortraitUpsideDown]) {
ret = ret | (1 << UIInterfaceOrientationPortraitUpsideDown);
}
if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationLandscapeRight]) {
ret = ret | (1 << UIInterfaceOrientationLandscapeRight);
}
if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationLandscapeLeft]) {
ret = ret | (1 << UIInterfaceOrientationLandscapeLeft);
}
return ret;
}
- (BOOL)supportsOrientation:(UIInterfaceOrientation)orientation
{
return [self.supportedOrientations containsObject:[NSNumber numberWithInt:orientation]];
}
- (UIWebView*)newCordovaViewWithFrame:(CGRect)bounds
{
return [[UIWebView alloc] initWithFrame:bounds];
}
- (NSString*)userAgent
{
if (_userAgent == nil) {
NSString* localBaseUserAgent;
if (self.baseUserAgent != nil) {
localBaseUserAgent = self.baseUserAgent;
} else {
localBaseUserAgent = [CDVUserAgentUtil originalUserAgent];
}
// Use our address as a unique number to append to the User-Agent.
_userAgent = [NSString stringWithFormat:@"%@ (%lld)", localBaseUserAgent, (long long)self];
}
return _userAgent;
}
- (void)createGapView
{
CGRect webViewBounds = self.view.bounds;
webViewBounds.origin = self.view.bounds.origin;
self.webView = [self newCordovaViewWithFrame:webViewBounds];
self.webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
[self.view addSubview:self.webView];
[self.view sendSubviewToBack:self.webView];
}
- (void)didReceiveMemoryWarning
{
// iterate through all the plugin objects, and call hasPendingOperation
// if at least one has a pending operation, we don't call [super didReceiveMemoryWarning]
NSEnumerator* enumerator = [self.pluginObjects objectEnumerator];
CDVPlugin* plugin;
BOOL doPurge = YES;
while ((plugin = [enumerator nextObject])) {
if (plugin.hasPendingOperation) {
// NSLog(@"Plugin '%@' has a pending operation, memory purge is delayed for didReceiveMemoryWarning.", NSStringFromClass([plugin class]));
doPurge = NO;
}
}
if (doPurge) {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
}
// Release any cached data, images, etc. that aren't in use.
}
- (void)viewDidUnload
{
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.webView.delegate = nil;
self.webView = nil;
[CDVUserAgentUtil releaseLock:&_userAgentLockToken];
[super viewDidUnload];
}
#pragma mark UIWebViewDelegate
/**
When web application loads Add stuff to the DOM, mainly the user-defined settings from the Settings.plist file, and
the device's data such as device ID, platform version, etc.
*/
- (void)webViewDidStartLoad:(UIWebView*)theWebView
{
// NSLog(@"Resetting plugins due to page load.");
[_commandQueue resetRequestId];
[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginResetNotification object:self.webView]];
}
/**
Called when the webview finishes loading. This stops the activity view.
*/
- (void)webViewDidFinishLoad:(UIWebView*)theWebView
{
// NSLog(@"Finished load of: %@", theWebView.request.URL);
// It's safe to release the lock even if this is just a sub-frame that's finished loading.
[CDVUserAgentUtil releaseLock:&_userAgentLockToken];
/*
* Hide the Top Activity THROBBER in the Battery Bar
*/
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPageDidLoadNotification object:self.webView]];
}
- (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error
{
[CDVUserAgentUtil releaseLock:&_userAgentLockToken];
NSString* message = [NSString stringWithFormat:@"Failed to load webpage with error: %@", [error localizedDescription]];
// NSLog(@"%@", message);
NSURL* errorUrl = [self errorUrl];
if (errorUrl) {
errorUrl = [NSURL URLWithString:[NSString stringWithFormat:@"?error=%@", [message stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]] relativeToURL:errorUrl];
// NSLog(@"%@", [errorUrl absoluteString]);
[theWebView loadRequest:[NSURLRequest requestWithURL:errorUrl]];
}
}
- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL* url = [request URL];
/*
* Execute any commands queued with cordova.exec() on the JS side.
* The part of the URL after gap:// is irrelevant.
*/
if ([[url scheme] isEqualToString:@"gap"]) {
[_commandQueue fetchCommandsFromJs];
// The delegate is called asynchronously in this case, so we don't have to use
// flushCommandQueueWithDelayedJs (setTimeout(0)) as we do with hash changes.
[_commandQueue executePending];
return NO;
}
if ([[url fragment] hasPrefix:@"%01"] || [[url fragment] hasPrefix:@"%02"]) {
// Delegate is called *immediately* for hash changes. This means that any
// calls to stringByEvaluatingJavascriptFromString will occur in the middle
// of an existing (paused) call stack. This doesn't cause errors, but may
// be unexpected to callers (exec callbacks will be called before exec() even
// returns). To avoid this, we do not do any synchronous JS evals by using
// flushCommandQueueWithDelayedJs.
NSString* inlineCommands = [[url fragment] substringFromIndex:3];
if ([inlineCommands length] == 0) {
// Reach in right away since the WebCore / Main thread are already synchronized.
[_commandQueue fetchCommandsFromJs];
} else {
inlineCommands = [inlineCommands stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[_commandQueue enqueueCommandBatch:inlineCommands];
}
// Switch these for minor performance improvements, and to really live on the wild side.
// Callbacks will occur in the middle of the location.hash = ... statement!
[(CDVCommandDelegateImpl*)_commandDelegate flushCommandQueueWithDelayedJs];
// [_commandQueue executePending];
// Although we return NO, the hash change does end up taking effect.
return NO;
}
/*
* Give plugins the chance to handle the url
*/
for (NSString* pluginName in pluginObjects) {
CDVPlugin* plugin = [pluginObjects objectForKey:pluginName];
SEL selector = NSSelectorFromString(@"shouldOverrideLoadWithRequest:navigationType:");
if ([plugin respondsToSelector:selector]) {
if (((BOOL (*)(id, SEL, id, int))objc_msgSend)(plugin, selector, request, navigationType) == YES) {
return NO;
}
}
}
/*
* If a URL is being loaded that's a file/http/https URL, just load it internally
*/
if ([url isFileURL]) {
return YES;
}
/*
* If we loaded the HTML from a string, we let the app handle it
*/
else if (self.loadFromString == YES) {
self.loadFromString = NO;
return YES;
}
/*
* all tel: scheme urls we let the UIWebview handle it using the default behavior
*/
else if ([[url scheme] isEqualToString:@"tel"]) {
return YES;
}
/*
* all about: scheme urls are not handled
*/
else if ([[url scheme] isEqualToString:@"about"]) {
return NO;
}
/*
* all data: scheme urls are handled
*/
else if ([[url scheme] isEqualToString:@"data"]) {
return YES;
}
/*
* Handle all other types of urls (tel:, sms:), and requests to load a url in the main webview.
*/
else {
if ([self.whitelist schemeIsAllowed:[url scheme]]) {
return [self.whitelist URLIsAllowed:url];
} else {
if ([[UIApplication sharedApplication] canOpenURL:url]) {
[[UIApplication sharedApplication] openURL:url];
} else { // handle any custom schemes to plugins
[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]];
}
}
return NO;
}
return YES;
}
#pragma mark GapHelpers
- (void)javascriptAlert:(NSString*)text
{
NSString* jsString = [NSString stringWithFormat:@"alert('%@');", text];
[self.commandDelegate evalJs:jsString];
}
+ (NSString*)applicationDocumentsDirectory
{
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* basePath = (([paths count] > 0) ? ([paths objectAtIndex : 0]) : nil);
return basePath;
}
#pragma mark CordovaCommands
- (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className
{
if ([plugin respondsToSelector:@selector(setViewController:)]) {
[plugin setViewController:self];
}
if ([plugin respondsToSelector:@selector(setCommandDelegate:)]) {
[plugin setCommandDelegate:_commandDelegate];
}
[self.pluginObjects setObject:plugin forKey:className];
[plugin pluginInitialize];
}
- (void)registerPlugin:(CDVPlugin*)plugin withPluginName:(NSString*)pluginName
{
if ([plugin respondsToSelector:@selector(setViewController:)]) {
[plugin setViewController:self];
}
if ([plugin respondsToSelector:@selector(setCommandDelegate:)]) {
[plugin setCommandDelegate:_commandDelegate];
}
NSString* className = NSStringFromClass([plugin class]);
[self.pluginObjects setObject:plugin forKey:className];
[self.pluginsMap setValue:className forKey:[pluginName lowercaseString]];
[plugin pluginInitialize];
}
/**
Returns an instance of a CordovaCommand object, based on its name. If one exists already, it is returned.
*/
- (id)getCommandInstance:(NSString*)pluginName
{
// first, we try to find the pluginName in the pluginsMap
// (acts as a whitelist as well) if it does not exist, we return nil
// NOTE: plugin names are matched as lowercase to avoid problems - however, a
// possible issue is there can be duplicates possible if you had:
// "org.apache.cordova.Foo" and "org.apache.cordova.foo" - only the lower-cased entry will match
NSString* className = [self.pluginsMap objectForKey:[pluginName lowercaseString]];
if (className == nil) {
return nil;
}
id obj = [self.pluginObjects objectForKey:className];
if (!obj) {
obj = [[NSClassFromString(className)alloc] initWithWebView:webView];
if (obj != nil) {
[self registerPlugin:obj withClassName:className];
} else {
// NSLog(@"CDVPlugin class %@ (pluginName: %@) does not exist.", className, pluginName);
}
}
return obj;
}
#pragma mark -
- (NSString*)appURLScheme
{
NSString* URLScheme = nil;
NSArray* URLTypes = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleURLTypes"];
if (URLTypes != nil) {
NSDictionary* dict = [URLTypes objectAtIndex:0];
if (dict != nil) {
NSArray* URLSchemes = [dict objectForKey:@"CFBundleURLSchemes"];
if (URLSchemes != nil) {
URLScheme = [URLSchemes objectAtIndex:0];
}
}
}
return URLScheme;
}
/**
Returns the contents of the named plist bundle, loaded as a dictionary object
*/
+ (NSDictionary*)getBundlePlist:(NSString*)plistName
{
NSString* errorDesc = nil;
NSPropertyListFormat format;
NSString* plistPath = [[NSBundle mainBundle] pathForResource:plistName ofType:@"plist"];
NSData* plistXML = [[NSFileManager defaultManager] contentsAtPath:plistPath];
NSDictionary* temp = (NSDictionary*)[NSPropertyListSerialization
propertyListFromData:plistXML
mutabilityOption:NSPropertyListMutableContainersAndLeaves
format:&format errorDescription:&errorDesc];
return temp;
}
#pragma mark -
#pragma mark UIApplicationDelegate impl
/*
This method lets your application know that it is about to be terminated and purged from memory entirely
*/
- (void)onAppWillTerminate:(NSNotification*)notification
{
// empty the tmp directory
NSFileManager* fileMgr = [[NSFileManager alloc] init];
NSError* __autoreleasing err = nil;
// clear contents of NSTemporaryDirectory
NSString* tempDirectoryPath = NSTemporaryDirectory();
NSDirectoryEnumerator* directoryEnumerator = [fileMgr enumeratorAtPath:tempDirectoryPath];
NSString* fileName = nil;
BOOL result;
while ((fileName = [directoryEnumerator nextObject])) {
NSString* filePath = [tempDirectoryPath stringByAppendingPathComponent:fileName];
result = [fileMgr removeItemAtPath:filePath error:&err];
if (!result && err) {
// NSLog(@"Failed to delete: %@ (error: %@)", filePath, err);
}
}
}
/*
This method is called to let your application know that it is about to move from the active to inactive state.
You should use this method to pause ongoing tasks, disable timer, ...
*/
- (void)onAppWillResignActive:(NSNotification*)notification
{
// NSLog(@"%@",@"applicationWillResignActive");
[self.commandDelegate evalJs:@"cordova.fireDocumentEvent('resign');" scheduledOnRunLoop:NO];
}
/*
In iOS 4.0 and later, this method is called as part of the transition from the background to the inactive state.
You can use this method to undo many of the changes you made to your application upon entering the background.
invariably followed by applicationDidBecomeActive
*/
- (void)onAppWillEnterForeground:(NSNotification*)notification
{
// NSLog(@"%@",@"applicationWillEnterForeground");
[self.commandDelegate evalJs:@"cordova.fireDocumentEvent('resume');"];
}
// This method is called to let your application know that it moved from the inactive to active state.
- (void)onAppDidBecomeActive:(NSNotification*)notification
{
// NSLog(@"%@",@"applicationDidBecomeActive");
[self.commandDelegate evalJs:@"cordova.fireDocumentEvent('active');"];
}
/*
In iOS 4.0 and later, this method is called instead of the applicationWillTerminate: method
when the user quits an application that supports background execution.
*/
- (void)onAppDidEnterBackground:(NSNotification*)notification
{
// NSLog(@"%@",@"applicationDidEnterBackground");
[self.commandDelegate evalJs:@"cordova.fireDocumentEvent('pause', null, true);" scheduledOnRunLoop:NO];
}
// ///////////////////////
- (void)onPageDidLoad:(NSNotification*)notification
{
if (self.openURL) {
[self processOpenUrl:self.openURL pageLoaded:YES];
self.openURL = nil;
}
}
- (void)processOpenUrl:(NSURL*)url pageLoaded:(BOOL)pageLoaded
{
if (!pageLoaded) {
// query the webview for readystate
NSString* readyState = [webView stringByEvaluatingJavaScriptFromString:@"document.readyState"];
pageLoaded = [readyState isEqualToString:@"loaded"] || [readyState isEqualToString:@"complete"];
}
if (pageLoaded) {
// calls into javascript global function 'handleOpenURL'
NSString* jsString = [NSString stringWithFormat:@"if (typeof handleOpenURL === 'function') { handleOpenURL(\"%@\");}", url];
[self.webView stringByEvaluatingJavaScriptFromString:jsString];
} else {
// save for when page has loaded
self.openURL = url;
}
}
- (void)processOpenUrl:(NSURL*)url
{
[self processOpenUrl:url pageLoaded:NO];
}
// ///////////////////////
- (void)dealloc
{
[CDVURLProtocol unregisterViewController:self];
[[NSNotificationCenter defaultCenter] removeObserver:self];
self.webView.delegate = nil;
self.webView = nil;
[CDVUserAgentUtil releaseLock:&_userAgentLockToken];
[_commandQueue dispose];
[[self.pluginObjects allValues] makeObjectsPerformSelector:@selector(dispose)];
}
@end
... ...
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import "CDVAvailability.h"
#import "CDVPlugin.h"
#import "CDVViewController.h"
#import "CDVCommandDelegate.h"
#import "CDVURLProtocol.h"
#import "CDVInvokedUrlCommand.h"
#import "CDVDebug.h"
#import "CDVPluginResult.h"
#import "CDVWhitelist.h"
#import "CDVLocalStorage.h"
#import "CDVScreenOrientationDelegate.h"
#import "CDVTimer.h"
#import "NSArray+Comparisons.h"
#import "NSData+Base64.h"
#import "NSDictionary+Extensions.h"
#import "NSMutableArray+QueueAdditions.h"
#import "UIDevice+Extensions.h"
#import "CDVJSON.h"
... ...
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import "CDVAvailabilityDeprecated.h"
#define __CORDOVA_IOS__
#define __CORDOVA_0_9_6 906
#define __CORDOVA_1_0_0 10000
#define __CORDOVA_1_1_0 10100
#define __CORDOVA_1_2_0 10200
#define __CORDOVA_1_3_0 10300
#define __CORDOVA_1_4_0 10400
#define __CORDOVA_1_4_1 10401
#define __CORDOVA_1_5_0 10500
#define __CORDOVA_1_6_0 10600
#define __CORDOVA_1_6_1 10601
#define __CORDOVA_1_7_0 10700
#define __CORDOVA_1_8_0 10800
#define __CORDOVA_1_8_1 10801
#define __CORDOVA_1_9_0 10900
#define __CORDOVA_2_0_0 20000
#define __CORDOVA_2_1_0 20100
#define __CORDOVA_2_2_0 20200
#define __CORDOVA_2_3_0 20300
#define __CORDOVA_2_4_0 20400
#define __CORDOVA_2_5_0 20500
#define __CORDOVA_2_6_0 20600
#define __CORDOVA_2_7_0 20700
#define __CORDOVA_2_8_0 20800
#define __CORDOVA_2_9_0 20900
#define __CORDOVA_3_0_0 30000
#define __CORDOVA_3_1_0 30100
#define __CORDOVA_3_2_0 30200
#define __CORDOVA_3_3_0 30300
#define __CORDOVA_3_4_0 30400
#define __CORDOVA_3_4_1 30401
#define __CORDOVA_3_5_0 30500
#define __CORDOVA_3_6_0 30600
#define __CORDOVA_3_7_0 30700
#define __CORDOVA_3_8_0 30800
#define __CORDOVA_NA 99999 /* not available */
/*
#if CORDOVA_VERSION_MIN_REQUIRED >= __CORDOVA_1_7_0
// do something when its at least 1.7.0
#else
// do something else (non 1.7.0)
#endif
*/
#ifndef CORDOVA_VERSION_MIN_REQUIRED
#define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_3_8_0
#endif
/*
Returns YES if it is at least version specified as NSString(X)
Usage:
if (IsAtLeastiOSVersion(@"5.1")) {
// do something for iOS 5.1 or greater
}
*/
#define IsAtLeastiOSVersion(X) ([[[UIDevice currentDevice] systemVersion] compare:X options:NSNumericSearch] != NSOrderedAscending)
/* Return the string version of the decimal version */
#define CDV_VERSION [NSString stringWithFormat:@"%d.%d.%d", \
(CORDOVA_VERSION_MIN_REQUIRED / 10000), \
(CORDOVA_VERSION_MIN_REQUIRED % 10000) / 100, \
(CORDOVA_VERSION_MIN_REQUIRED % 10000) % 100]
// Enable this to log all exec() calls.
#define CDV_ENABLE_EXEC_LOGGING 0
#if CDV_ENABLE_EXEC_LOGGING
#define CDV_EXEC_LOG NSLog
#else
#define CDV_EXEC_LOG(...) do {} while (NO)
#endif
... ...
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import <UIKit/UIKit.h>
#ifdef __clang__
#define CDV_DEPRECATED(version, msg) __attribute__((deprecated("Deprecated in Cordova " #version ". " msg)))
#else
#define CDV_DEPRECATED(version, msg) __attribute__((deprecated()))
#endif
static inline BOOL CDV_IsIPad(void) CDV_DEPRECATED(3.7.0, "This will be removed in 4.0.0");
static inline BOOL CDV_IsIPhone5(void) CDV_DEPRECATED(3.7.0, "This will be removed in 4.0.0");
static inline BOOL CDV_IsIPad(void) {
return [[UIDevice currentDevice] respondsToSelector:@selector(userInterfaceIdiom)] && [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad;
}
static inline BOOL CDV_IsIPhone5(void) {
return ([[UIScreen mainScreen] bounds].size.width == 568 && [[UIScreen mainScreen] bounds].size.height == 320) || ([[UIScreen mainScreen] bounds].size.height == 568 && [[UIScreen mainScreen] bounds].size.width == 320);
}
\ No newline at end of file
... ...
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import "CDVAvailability.h"
#import "CDVInvokedUrlCommand.h"
@class CDVPlugin;
@class CDVPluginResult;
@class CDVWhitelist;
@protocol CDVCommandDelegate <NSObject>
@property (nonatomic, readonly) NSDictionary* settings;
- (NSString*)pathForResource:(NSString*)resourcepath;
- (id)getCommandInstance:(NSString*)pluginName;
// Sends a plugin result to the JS. This is thread-safe.
- (void)sendPluginResult:(CDVPluginResult*)result callbackId:(NSString*)callbackId;
// Evaluates the given JS. This is thread-safe.
- (void)evalJs:(NSString*)js;
// Can be used to evaluate JS right away instead of scheduling it on the run-loop.
// This is required for dispatch resign and pause events, but should not be used
// without reason. Without the run-loop delay, alerts used in JS callbacks may result
// in dead-lock. This method must be called from the UI thread.
- (void)evalJs:(NSString*)js scheduledOnRunLoop:(BOOL)scheduledOnRunLoop;
// Runs the given block on a background thread using a shared thread-pool.
- (void)runInBackground:(void (^)())block;
// Returns the User-Agent of the associated UIWebView.
- (NSString*)userAgent;
// Returns whether the given URL passes the white-list.
- (BOOL)URLIsWhitelisted:(NSURL*)url;
@end
... ...
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import <UIKit/UIKit.h>
#import "CDVCommandDelegate.h"
@class CDVViewController;
@class CDVCommandQueue;
@interface CDVCommandDelegateImpl : NSObject <CDVCommandDelegate>{
@private
__weak CDVViewController* _viewController;
NSRegularExpression* _callbackIdPattern;
@protected
__weak CDVCommandQueue* _commandQueue;
BOOL _delayResponses;
}
- (id)initWithViewController:(CDVViewController*)viewController;
- (void)flushCommandQueueWithDelayedJs;
@end
... ...
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import "CDVCommandDelegateImpl.h"
#import "CDVJSON_private.h"
#import "CDVCommandQueue.h"
#import "CDVPluginResult.h"
#import "CDVViewController.h"
@implementation CDVCommandDelegateImpl
- (id)initWithViewController:(CDVViewController*)viewController
{
self = [super init];
if (self != nil) {
_viewController = viewController;
_commandQueue = _viewController.commandQueue;
NSError* err = nil;
_callbackIdPattern = [NSRegularExpression regularExpressionWithPattern:@"[^A-Za-z0-9._-]" options:0 error:&err];
if (err != nil) {
// Couldn't initialize Regex
// NSLog(@"Error: Couldn't initialize regex");
_callbackIdPattern = nil;
}
}
return self;
}
- (NSString*)pathForResource:(NSString*)resourcepath
{
NSBundle* mainBundle = [NSBundle mainBundle];
NSMutableArray* directoryParts = [NSMutableArray arrayWithArray:[resourcepath componentsSeparatedByString:@"/"]];
NSString* filename = [directoryParts lastObject];
[directoryParts removeLastObject];
NSString* directoryPartsJoined = [directoryParts componentsJoinedByString:@"/"];
NSString* directoryStr = _viewController.wwwFolderName;
if ([directoryPartsJoined length] > 0) {
directoryStr = [NSString stringWithFormat:@"%@/%@", _viewController.wwwFolderName, [directoryParts componentsJoinedByString:@"/"]];
}
return [mainBundle pathForResource:filename ofType:@"" inDirectory:directoryStr];
}
- (void)flushCommandQueueWithDelayedJs
{
_delayResponses = YES;
[_commandQueue executePending];
_delayResponses = NO;
}
- (void)evalJsHelper2:(NSString*)js
{
CDV_EXEC_LOG(@"Exec: evalling: %@", [js substringToIndex:MIN([js length], 160)]);
NSString* commandsJSON = [_viewController.webView stringByEvaluatingJavaScriptFromString:js];
if ([commandsJSON length] > 0) {
CDV_EXEC_LOG(@"Exec: Retrieved new exec messages by chaining.");
}
[_commandQueue enqueueCommandBatch:commandsJSON];
[_commandQueue executePending];
}
- (void)evalJsHelper:(NSString*)js
{
// Cycle the run-loop before executing the JS.
// For _delayResponses -
// This ensures that we don't eval JS during the middle of an existing JS
// function (possible since UIWebViewDelegate callbacks can be synchronous).
// For !isMainThread -
// It's a hard error to eval on the non-UI thread.
// For !_commandQueue.currentlyExecuting -
// This works around a bug where sometimes alerts() within callbacks can cause
// dead-lock.
// If the commandQueue is currently executing, then we know that it is safe to
// execute the callback immediately.
// Using (dispatch_get_main_queue()) does *not* fix deadlocks for some reason,
// but performSelectorOnMainThread: does.
if (_delayResponses || ![NSThread isMainThread] || !_commandQueue.currentlyExecuting) {
[self performSelectorOnMainThread:@selector(evalJsHelper2:) withObject:js waitUntilDone:NO];
} else {
[self evalJsHelper2:js];
}
}
- (BOOL)isValidCallbackId:(NSString*)callbackId
{
if ((callbackId == nil) || (_callbackIdPattern == nil)) {
return NO;
}
// Disallow if too long or if any invalid characters were found.
if (([callbackId length] > 100) || [_callbackIdPattern firstMatchInString:callbackId options:0 range:NSMakeRange(0, [callbackId length])]) {
return NO;
}
return YES;
}
- (void)sendPluginResult:(CDVPluginResult*)result callbackId:(NSString*)callbackId
{
CDV_EXEC_LOG(@"Exec(%@): Sending result. Status=%@", callbackId, result.status);
// This occurs when there is are no win/fail callbacks for the call.
if ([@"INVALID" isEqualToString : callbackId]) {
return;
}
// This occurs when the callback id is malformed.
if (![self isValidCallbackId:callbackId]) {
// NSLog(@"Invalid callback id received by sendPluginResult");
return;
}
int status = [result.status intValue];
BOOL keepCallback = [result.keepCallback boolValue];
NSString* argumentsAsJSON = [result argumentsAsJSON];
NSString* js = [NSString stringWithFormat:@"cordova.require('cordova/exec').nativeCallback('%@',%d,%@,%d)", callbackId, status, argumentsAsJSON, keepCallback];
[self evalJsHelper:js];
}
- (void)evalJs:(NSString*)js
{
[self evalJs:js scheduledOnRunLoop:YES];
}
- (void)evalJs:(NSString*)js scheduledOnRunLoop:(BOOL)scheduledOnRunLoop
{
js = [NSString stringWithFormat:@"cordova.require('cordova/exec').nativeEvalAndFetch(function(){%@})", js];
if (scheduledOnRunLoop) {
[self evalJsHelper:js];
} else {
[self evalJsHelper2:js];
}
}
- (id)getCommandInstance:(NSString*)pluginName
{
return [_viewController getCommandInstance:pluginName];
}
- (void)runInBackground:(void (^)())block
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
}
- (NSString*)userAgent
{
return [_viewController userAgent];
}
- (BOOL)URLIsWhitelisted:(NSURL*)url
{
return ![_viewController.whitelist schemeIsAllowed:[url scheme]] ||
[_viewController.whitelist URLIsAllowed:url logFailure:NO];
}
- (NSDictionary*)settings
{
return _viewController.settings;
}
@end
... ...
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import "CDVPlugin.h"
@interface CDVHandleOpenURL : CDVPlugin
@property (nonatomic, strong) NSURL* url;
@property (nonatomic, assign) BOOL pageLoaded;
@end
... ...
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import "CDVHandleOpenURL.h"
#import "CDV.h"
@implementation CDVHandleOpenURL
- (void)pluginInitialize
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationLaunchedWithUrl:) name:CDVPluginHandleOpenURLNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationPageDidLoad:) name:CDVPageDidLoadNotification object:nil];
}
- (void)applicationLaunchedWithUrl:(NSNotification*)notification
{
NSURL *url = [notification object];
self.url = url;
// warm-start handler
if (self.pageLoaded) {
[self processOpenUrl:self.url pageLoaded:YES];
self.url = nil;
}
}
- (void)applicationPageDidLoad:(NSNotification*)notification
{
// cold-start handler
self.pageLoaded = YES;
if (self.url) {
[self processOpenUrl:self.url pageLoaded:YES];
self.url = nil;
}
}
- (void)processOpenUrl:(NSURL*)url pageLoaded:(BOOL)pageLoaded
{
if (!pageLoaded) {
// query the webview for readystate
NSString* readyState = [self.webView stringByEvaluatingJavaScriptFromString:@"document.readyState"];
pageLoaded = [readyState isEqualToString:@"loaded"] || [readyState isEqualToString:@"complete"];
}
if (pageLoaded) {
// calls into javascript global function 'handleOpenURL'
NSString* jsString = [NSString stringWithFormat:@"document.addEventListener('deviceready',function(){if (typeof handleOpenURL === 'function') { handleOpenURL(\"%@\");}});", url];
[self.webView stringByEvaluatingJavaScriptFromString:jsString];
} else {
// save for when page has loaded
self.url = url;
}
}
@end
... ...
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import <Foundation/Foundation.h>
@interface CDVInvokedUrlCommand : NSObject {
NSString* _callbackId;
NSString* _className;
NSString* _methodName;
NSArray* _arguments;
}
@property (nonatomic, readonly) NSArray* arguments;
@property (nonatomic, readonly) NSString* callbackId;
@property (nonatomic, readonly) NSString* className;
@property (nonatomic, readonly) NSString* methodName;
+ (CDVInvokedUrlCommand*)commandFromJson:(NSArray*)jsonEntry;
- (id)initWithArguments:(NSArray*)arguments
callbackId:(NSString*)callbackId
className:(NSString*)className
methodName:(NSString*)methodName;
- (id)initFromJson:(NSArray*)jsonEntry;
// Returns the argument at the given index.
// If index >= the number of arguments, returns nil.
// If the argument at the given index is NSNull, returns nil.
- (id)argumentAtIndex:(NSUInteger)index;
// Same as above, but returns defaultValue instead of nil.
- (id)argumentAtIndex:(NSUInteger)index withDefault:(id)defaultValue;
// Same as above, but returns defaultValue instead of nil, and if the argument is not of the expected class, returns defaultValue
- (id)argumentAtIndex:(NSUInteger)index withDefault:(id)defaultValue andClass:(Class)aClass;
@end
... ...