757 lines
16 KiB
PHP
757 lines
16 KiB
PHP
<?php
|
|
|
|
namespace Bitrix\MobileApp;
|
|
|
|
use Bitrix\Main\Application;
|
|
use Bitrix\Main\Context;
|
|
use Bitrix\Main\IO\File;
|
|
use Bitrix\Main\Text\Encoding;
|
|
|
|
class Mobile
|
|
{
|
|
public static $platform = "ios";
|
|
public static $apiVersion = 1;
|
|
public static $pgVersion = "2.0.0";
|
|
public static $supportedCordovaVersion = "3.6.3";
|
|
public static $isDev = false;
|
|
protected static $instance;
|
|
protected static $isAlreadyInit = false;
|
|
protected static $systemVersion = 9;
|
|
private $pixelRatio = 1.0;
|
|
private $minScale = false;
|
|
private $iniScale = false;
|
|
private $maxScale = false;
|
|
private $scale = 1.2;
|
|
private $width = false;
|
|
private $userScalable = "no";
|
|
private $deviceWidth = 320;
|
|
private $deviceHeight = 480;
|
|
private $screenCategory = "NORMAL";
|
|
private $device = "";
|
|
private $largeScreenSupport = true;
|
|
private $isWebRtcSupported = false;
|
|
private $isBXScriptSupported = false;
|
|
|
|
private function __construct()
|
|
{
|
|
global $APPLICATION;
|
|
|
|
$this->setDeviceWidth($_COOKIE["MOBILE_RESOLUTION_WIDTH"] ?? null);
|
|
$this->setDeviceHeight($_COOKIE["MOBILE_RESOLUTION_HEIGHT"] ?? null);
|
|
$this->setPixelratio($_COOKIE["MOBILE_SCALE"] ?? null);
|
|
$this->screenCategory = $_COOKIE["MOBILE_SCREEN_CATEGORY"] ?? null;
|
|
|
|
if (!empty($_COOKIE["PG_VERSION"]))
|
|
{
|
|
self::$pgVersion = $_COOKIE["PG_VERSION"];
|
|
}
|
|
|
|
self::$isDev = (isset($_COOKIE["MOBILE_DEV"]) && $_COOKIE["MOBILE_DEV"] == "Y");
|
|
$this->device = $_COOKIE["MOBILE_DEVICE"] ?? null;
|
|
if (!empty($_COOKIE["IS_WEBRTC_SUPPORTED"]) && $_COOKIE["IS_WEBRTC_SUPPORTED"] == "Y")
|
|
{
|
|
$this->setWebRtcSupport(true);
|
|
}
|
|
if (!empty($_COOKIE["IS_BXSCRIPT_SUPPORTED"]) && $_COOKIE["IS_BXSCRIPT_SUPPORTED"] == "Y")
|
|
{
|
|
$this->setBXScriptSupported(true);
|
|
}
|
|
|
|
if ($this->getDevice() == "iPad")
|
|
{
|
|
$this->setScreenCategory("LARGE");
|
|
if (intval($this->getPixelRatio()) == 2) //retina hack
|
|
{
|
|
$this->setDeviceWidth($_COOKIE["MOBILE_RESOLUTION_WIDTH"] / 2);
|
|
$this->setDeviceHeight($_COOKIE["MOBILE_RESOLUTION_HEIGHT"] / 2);
|
|
}
|
|
}
|
|
|
|
//detecting OS
|
|
if (array_key_exists("MOBILE_DEVICE", $_COOKIE))
|
|
{
|
|
$deviceDetectSource = $_COOKIE["MOBILE_DEVICE"];
|
|
}
|
|
else
|
|
{
|
|
$deviceDetectSource = mb_strtolower(Context::getCurrent()->getServer()->get("HTTP_USER_AGENT"));
|
|
}
|
|
|
|
if (mb_strrpos(mb_strtoupper($deviceDetectSource), "IPHONE") > 0 || mb_strrpos(mb_strtoupper($deviceDetectSource), "IPAD") > 0)
|
|
{
|
|
self::$platform = "ios";
|
|
}
|
|
elseif (mb_strrpos(mb_strtoupper($deviceDetectSource), "ANDROID") > 0 || mb_strrpos(mb_strtoupper($deviceDetectSource), "ANDROID") === 0)
|
|
{
|
|
self::$platform = "android";
|
|
}
|
|
|
|
$userAgent = \Bitrix\Main\Context::getCurrent()->getServer()->get("HTTP_USER_AGENT");
|
|
if (!empty($_COOKIE["MOBILE_SYSTEM_VERSION"]))
|
|
{
|
|
self::$systemVersion = $_COOKIE["MOBILE_SYSTEM_VERSION"];
|
|
}
|
|
else
|
|
{
|
|
//iOS
|
|
preg_match("/iOS\s(\d+\.\d+)/i",$userAgent, $pregMatch);
|
|
if(count($pregMatch) == 2)
|
|
self::$systemVersion = floatval($pregMatch[1]);
|
|
}
|
|
|
|
if (array_key_exists("emulate_platform", $_REQUEST))
|
|
{
|
|
self::$platform = $_REQUEST["emulate_platform"];
|
|
}
|
|
|
|
if ($mobileTZ = $APPLICATION->get_cookie("TZ", "MOBILE")) {
|
|
$tz = $APPLICATION->get_cookie("TZ");
|
|
if ($tz != $mobileTZ) {
|
|
$cookie = new \Bitrix\Main\Web\Cookie("TZ", $mobileTZ, time() + 60 * 60 * 24 * 30 * 12);
|
|
\Bitrix\Main\Context::getCurrent()->getResponse()->addCookie($cookie);
|
|
}
|
|
|
|
}
|
|
|
|
if (array_key_exists("MOBILE_API_VERSION", $_COOKIE))
|
|
{
|
|
self::$apiVersion = $_COOKIE["MOBILE_API_VERSION"];
|
|
}
|
|
elseif ($APPLICATION->get_cookie("MOBILE_APP_VERSION"))
|
|
{
|
|
self::$apiVersion = $APPLICATION->get_cookie("MOBILE_APP_VERSION");
|
|
}
|
|
elseif (array_key_exists("api_version", $_REQUEST))
|
|
{
|
|
self::$apiVersion = $_REQUEST["api_version"];
|
|
}
|
|
else
|
|
{
|
|
preg_match("/(?<=BitrixMobile\/Version=).*\d/i",$userAgent, $pregMatch);
|
|
|
|
if(count($pregMatch) == 1)
|
|
{
|
|
self::$apiVersion = $pregMatch[0];
|
|
}
|
|
}
|
|
|
|
self::$apiVersion = intval(self::$apiVersion);
|
|
}
|
|
|
|
/**
|
|
* @param boolean $isWebRtcSupported
|
|
*/
|
|
public function setWebRtcSupport($isWebRtcSupported)
|
|
{
|
|
$this->isWebRtcSupported = $isWebRtcSupported;
|
|
}
|
|
|
|
/**
|
|
* @param boolean $isBXScriptSupported
|
|
*/
|
|
public function setBXScriptSupported($isBXScriptSupported)
|
|
{
|
|
$this->isBXScriptSupported = $isBXScriptSupported;
|
|
}
|
|
|
|
/**
|
|
* Return type of current device
|
|
* @return string
|
|
*/
|
|
public function getDevice()
|
|
{
|
|
return $this->device;
|
|
}
|
|
|
|
/**
|
|
* Gets the value of pixelRatio.
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function getPixelRatio()
|
|
{
|
|
return $this->pixelRatio;
|
|
}
|
|
|
|
/**
|
|
* Sets the value of pixelRatio.
|
|
*
|
|
* @param mixed $pixelRatio the pixelRatio
|
|
*/
|
|
public function setPixelRatio($pixelRatio)
|
|
{
|
|
$this->pixelRatio = $pixelRatio;
|
|
}
|
|
|
|
/**
|
|
* Returns true if mobile application made this request in background
|
|
* @return bool
|
|
*/
|
|
public static function isAppBackground()
|
|
{
|
|
$isBackground = Context::getCurrent()->getServer()->get("HTTP_BX_MOBILE_BACKGROUND");
|
|
return ($isBackground === "true");
|
|
}
|
|
|
|
/**
|
|
* Initiate the mobile platform
|
|
*/
|
|
public static function Init()
|
|
{
|
|
self::getInstance()->_Init();
|
|
}
|
|
|
|
/**
|
|
* detects mobile platform and attaches all needed javascript files
|
|
*/
|
|
protected function _Init()
|
|
{
|
|
if (self::$isAlreadyInit)
|
|
{
|
|
return;
|
|
}
|
|
|
|
header("BX-Cordova-Version: " . self::$supportedCordovaVersion);
|
|
$GLOBALS["BITRIX_PLATFORM"] = self::$platform;
|
|
$GLOBALS["BITRIX_API_VERSION"] = self::$apiVersion;
|
|
|
|
AddEventHandler("main", "OnBeforeEndBufferContent", Array(__CLASS__, "initScripts"));
|
|
AddEventHandler("main", "OnEpilog", Array($this, "onMobileInit"));
|
|
self::$isAlreadyInit = true;
|
|
}
|
|
|
|
/**
|
|
* @return \Bitrix\MobileApp\Mobile
|
|
*/
|
|
public static function getInstance()
|
|
{
|
|
if (is_null(self::$instance))
|
|
{
|
|
self::$instance = new Mobile();
|
|
}
|
|
|
|
return self::$instance;
|
|
}
|
|
|
|
/**
|
|
* Sets viewport-metadata
|
|
*/
|
|
public static function initScripts()
|
|
{
|
|
global $APPLICATION, $USER;
|
|
|
|
\CJSCore::Init();
|
|
\CJSCore::Init("db");
|
|
$jsVarsFormat = <<<JSCODE
|
|
<script>
|
|
(window.BX||top.BX).message({ 'USER_ID': '%s'});
|
|
var appVersion = "%s";
|
|
var platform = "%s";
|
|
var mobileSiteDir = "%s";
|
|
</script>
|
|
|
|
JSCODE;
|
|
|
|
$APPLICATION->AddHeadString(
|
|
sprintf($jsVarsFormat,
|
|
$USER->getId(),
|
|
self::$apiVersion,
|
|
self::$platform,
|
|
SITE_DIR
|
|
), false, true);
|
|
|
|
if (self::$platform == "android")
|
|
{
|
|
/**
|
|
* This is workaround for android
|
|
* We use console.log() to tell the application about successful loading of this page
|
|
*/
|
|
$androidJS = <<<JSCODE
|
|
<script>
|
|
console.log("bxdata://success");
|
|
</script>
|
|
JSCODE;
|
|
|
|
$APPLICATION->AddHeadString($androidJS, false, true);
|
|
}
|
|
$userAgent = \Bitrix\Main\Context::getCurrent()->getServer()->get("HTTP_USER_AGENT");
|
|
if(mb_strpos($userAgent, "WKWebView/BitrixMobile") === false)
|
|
{
|
|
$pgJsFile = "/bitrix/js/mobileapp/__deviceload__/cordova.js?mod=1";
|
|
$APPLICATION->AddHeadString("<script src='$pgJsFile'></script>", false, true);
|
|
}
|
|
|
|
|
|
$APPLICATION->AddHeadString("<script src=\"" . \CUtil::GetAdditionalFileURL("/bitrix/js/mobileapp/bitrix_mobile.js") . "\"></script>", false, true);
|
|
$APPLICATION->AddHeadString("<script src=\"" . \CUtil::GetAdditionalFileURL("/bitrix/js/mobileapp/mobile_lib.js") . "\"></script>", false, true);
|
|
|
|
|
|
if (self::$platform == "android")
|
|
{
|
|
$APPLICATION->AddHeadString("<script>app.bindloadPageBlank();</script>", false, false);
|
|
}
|
|
|
|
if (!array_key_exists("doNotUseViewPort", $_REQUEST))
|
|
{
|
|
$APPLICATION->AddHeadString(Mobile::getInstance()->getViewPort());
|
|
}
|
|
|
|
\Bitrix\Main\UI\Extension::load([
|
|
'mobile.ajax'
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @return boolean
|
|
*/
|
|
public function getBXScriptSupported()
|
|
{
|
|
return $this->isBXScriptSupported;
|
|
}
|
|
|
|
/**
|
|
* Use it to get current value of "viewport"-metadata
|
|
*
|
|
* @param string $width
|
|
*
|
|
* @return mixed|string
|
|
*/
|
|
public function getViewPort($width = "")
|
|
{
|
|
|
|
if ($width == "")
|
|
{
|
|
$width = $this->getDevicewidth();
|
|
}
|
|
|
|
if ($this->largeScreenSupport == true)
|
|
{
|
|
//we need to change densitydpi for large screens
|
|
if ($this->getDevice() == "iPad")
|
|
{
|
|
//ipad large screen setting
|
|
return $this->getIPadViewPort();
|
|
|
|
}
|
|
elseif (($this->getScreenCategory() == "LARGE" || $this->getScreenCategory() == "XLARGE"))
|
|
{
|
|
//android large screen setting
|
|
return $this->getLargeScreenViewPort();
|
|
}
|
|
}
|
|
|
|
$viewPortMeta = "<meta id=\"bx_mobile_viewport\" name=\"viewport\" content=\"#content_value#\">";
|
|
if ($this->getIniscale())
|
|
{
|
|
$contentAttributes[] = "initial-scale=" . $this->getIniscale();
|
|
}
|
|
if ($this->getMaxscale())
|
|
{
|
|
$contentAttributes[] = "maximum-scale=" . $this->getMaxscale();
|
|
}
|
|
if ($this->getMinscale())
|
|
{
|
|
$contentAttributes[] = "minimum-scale=" . $this->getMinscale();
|
|
}
|
|
|
|
|
|
if ($this->getWidth())
|
|
{
|
|
$contentAttributes[] = "width=" . $this->getWidth();
|
|
}
|
|
elseif ($this->getIniscale())
|
|
{
|
|
$contentAttributes[] = "width=" . ($width / $this->getIniscale());
|
|
}
|
|
|
|
if (!$this->getWidth())
|
|
{
|
|
$contentAttributes[] = "width=device-width";
|
|
}
|
|
|
|
|
|
$contentAttributes[] = "user-scalable=" . $this->getUserScalable();
|
|
$contentAttributes[] = "viewport-fit=cover";
|
|
|
|
return str_replace("#content_value#", implode(", ", $contentAttributes), $viewPortMeta);
|
|
}
|
|
|
|
/**
|
|
* Gets the value of deviceWidth.
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function getDeviceWidth()
|
|
{
|
|
return $this->deviceWidth;
|
|
}
|
|
|
|
/**
|
|
* Sets the value of deviceWidth.
|
|
*
|
|
* @param mixed $deviceWidth the deviceWidth
|
|
*/
|
|
public function setDeviceWidth($deviceWidth)
|
|
{
|
|
$this->deviceWidth = $deviceWidth;
|
|
}
|
|
|
|
/**
|
|
* Use it to get value of viewport-metadata for iPad.
|
|
*
|
|
* @param int $width
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function getIPadViewPort($width = 320)
|
|
{
|
|
if ($width == false)
|
|
{
|
|
$width = $this->getDevicewidth();
|
|
}
|
|
$viewPortMeta = "<meta id=\"bx_mobile_viewport\" name=\"viewport\" content=\"#content_value#\">";
|
|
$contentAttributes = Array(
|
|
"width=" . ($width / $this->scale),
|
|
"user-scalable=no"
|
|
);
|
|
$content = implode(", ", $contentAttributes);
|
|
|
|
return str_replace("#content_value#", $content, $viewPortMeta);
|
|
}
|
|
|
|
/**
|
|
* Gets the value of deviceDpi.
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function getScreenCategory()
|
|
{
|
|
return $this->screenCategory;
|
|
}
|
|
|
|
/**
|
|
* Sets the value of screenCategory.
|
|
*
|
|
* @param mixed $screenCategory the screenCategory
|
|
*/
|
|
public function setScreenCategory($screenCategory)
|
|
{
|
|
$this->screenCategory = $screenCategory;
|
|
}
|
|
|
|
/**
|
|
* Use it to get value of viewport-metadata for large screen of android based device.
|
|
*/
|
|
public function getLargeScreenViewPort()
|
|
{
|
|
return "<meta id=\"bx_mobile_viewport\" name=\"viewport\" content=\"user-scalable=no width=device-width target-densitydpi=" . $this->getTargetDpi() . "\">";
|
|
}
|
|
|
|
/**
|
|
* Gets target dpi for a viewport meta data
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getTargetDpi()
|
|
{
|
|
$targetDpi = "medium-dpi";
|
|
if ($this->getDevice() == "iPad")
|
|
{
|
|
return $targetDpi;
|
|
}
|
|
switch ($this->getScreenCategory())
|
|
{
|
|
case 'NORMAL':
|
|
$targetDpi = "medium-dpi";
|
|
break;
|
|
case 'LARGE':
|
|
$targetDpi = "low-dpi";
|
|
break;
|
|
case 'XLARGE':
|
|
$targetDpi = "low-dpi";
|
|
break;
|
|
case 'SMALL':
|
|
$targetDpi = "medium-dpi";
|
|
break;
|
|
default:
|
|
$targetDpi = "medium-dpi";
|
|
break;
|
|
}
|
|
|
|
return $targetDpi;
|
|
}
|
|
|
|
/**
|
|
* Gets the value of iniScale.
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function getIniScale()
|
|
{
|
|
return $this->iniScale;
|
|
}
|
|
|
|
/**
|
|
* Sets the value of iniScale.
|
|
*
|
|
* @param mixed $iniScale the iniScale
|
|
*/
|
|
public function setIniScale($iniScale)
|
|
{
|
|
$this->iniScale = $iniScale;
|
|
}
|
|
|
|
/**
|
|
* Gets the value of maxScale.
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function getMaxScale()
|
|
{
|
|
return $this->maxScale;
|
|
}
|
|
|
|
/**
|
|
* Sets the value of maxScale.
|
|
*
|
|
* @param mixed $maxScale the maxScale
|
|
*/
|
|
public function setMaxScale($maxScale)
|
|
{
|
|
$this->maxScale = $maxScale;
|
|
}
|
|
|
|
/**
|
|
* Gets the value of minScale.
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function getMinScale()
|
|
{
|
|
return $this->minScale;
|
|
}
|
|
|
|
/**
|
|
* Sets the value of minScale.
|
|
*
|
|
* @param mixed $minScale the minScale
|
|
*/
|
|
public function setMinScale($minScale)
|
|
{
|
|
$this->minScale = $minScale;
|
|
}
|
|
|
|
/**
|
|
* Return width of device's screen in pixels
|
|
* @return integer
|
|
*/
|
|
public function getWidth()
|
|
{
|
|
return $this->width;
|
|
}
|
|
|
|
/**
|
|
* @param integer $width
|
|
*/
|
|
public function setWidth($width)
|
|
{
|
|
$this->width = $width;
|
|
}
|
|
|
|
/**
|
|
* Returns the value of self::platform
|
|
* @return string
|
|
*/
|
|
public static function getPlatform()
|
|
{
|
|
return self::$platform;
|
|
}
|
|
|
|
/**
|
|
* Returns value of parameter user-scalable which will be used in viewport meta tag
|
|
* @return string
|
|
*/
|
|
public function getUserScalable()
|
|
{
|
|
return $this->userScalable;
|
|
}
|
|
|
|
/**
|
|
* Sets value of parameter "user-scalable" which will be used in viewport meta tag
|
|
* @param boolean $userScalable
|
|
*/
|
|
public function setUserScalable($userScalable)
|
|
{
|
|
$this->userScalable = ($userScalable === false ? "no" : "yes");
|
|
}
|
|
|
|
/**
|
|
* @deprecated Does nothing.
|
|
* Converts string from site charset in utf-8 and returns it
|
|
*
|
|
* @param string $s
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function PrepareStrToJson($s = '')
|
|
{
|
|
return $s;
|
|
}
|
|
|
|
/**
|
|
* @deprecated Does nothing.
|
|
* Converts string from utf-8 in site charset and returns it
|
|
*
|
|
* @param string $s
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function ConvertFromUtf($s = '')
|
|
{
|
|
return $s;
|
|
}
|
|
|
|
public static function onMobileInit()
|
|
{
|
|
if (!defined("MOBILE_INIT_EVENT_SKIP"))
|
|
{
|
|
$db_events = getModuleEvents("mobileapp", "OnMobileInit");
|
|
while ($arEvent = $db_events->Fetch())
|
|
{
|
|
ExecuteModuleEventEx($arEvent);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the value of self::$apiVersion
|
|
*
|
|
* @return int
|
|
*/
|
|
public static function getApiVersion()
|
|
{
|
|
return self::$apiVersion;
|
|
}
|
|
|
|
/**
|
|
* Returns phonegap version
|
|
* @return string
|
|
*/
|
|
public static function getPgVersion()
|
|
{
|
|
return self::$pgVersion;
|
|
}
|
|
|
|
/**
|
|
* @return float
|
|
*/
|
|
public static function getSystemVersion()
|
|
{
|
|
return (float) self::$systemVersion;
|
|
}
|
|
|
|
/**
|
|
* @return boolean
|
|
*/
|
|
public function isWebRtcSupported()
|
|
{
|
|
return $this->isWebRtcSupported;
|
|
}
|
|
|
|
/**
|
|
* Use it to get value of viewport-metadata for portrait orientation.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getViewPortPortrait()
|
|
{
|
|
return $this->getViewPort($this->deviceWidth);
|
|
}
|
|
|
|
/**
|
|
* Use it to get value of viewport-metadata for landscape orientation.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getViewPortLandscape()
|
|
{
|
|
return $this->getViewPort($this->deviceHeight);
|
|
}
|
|
|
|
/**
|
|
* Gets the value of deviceHeight.
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function getDeviceHeight()
|
|
{
|
|
return $this->deviceHeight;
|
|
}
|
|
|
|
/**
|
|
* Sets the value of deviceHeight.
|
|
*
|
|
* @param mixed $deviceHeight the deviceHeight
|
|
*/
|
|
public function setDeviceHeight($deviceHeight)
|
|
{
|
|
$this->deviceHeight = $deviceHeight;
|
|
}
|
|
|
|
/**
|
|
* Gets the value of largeScreenSupport.
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function getLargeScreenSupport()
|
|
{
|
|
return $this->largeScreenSupport;
|
|
}
|
|
|
|
/**
|
|
* Sets the value of largeScreenSupport.
|
|
*
|
|
* @param mixed $largeScreenSupport the $largeScreenSupport
|
|
*/
|
|
public function setLargeScreenSupport($largeScreenSupport)
|
|
{
|
|
$this->largeScreenSupport = $largeScreenSupport;
|
|
}
|
|
|
|
/**
|
|
* Gets the value of scale.
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function getScale()
|
|
{
|
|
return $this->scale;
|
|
}
|
|
|
|
/**
|
|
* Sets the value of scale.
|
|
*
|
|
* @param $scale
|
|
*/
|
|
|
|
public function setScale($scale)
|
|
{
|
|
$this->scale = $scale;
|
|
}
|
|
|
|
/**
|
|
* Returns true if device has a large screen
|
|
* @return bool
|
|
*/
|
|
public function isLarge()
|
|
{
|
|
return ($this->getScreenCategory() == "LARGE" || $this->getScreenCategory() == "XLARGE");
|
|
}
|
|
|
|
private function __clone()
|
|
{
|
|
//you can't clone it
|
|
}
|
|
}
|
|
|
|
?>
|