From ef001b4977649a06fd770d725359f1754f3bb4e2 Mon Sep 17 00:00:00 2001 From: weiqiangliu Date: Thu, 1 Jun 2023 18:46:55 +0800 Subject: [PATCH] Release 4.0.0-beta --- build.gradle | 46 +- demo/.gitignore | 1 + demo/build.gradle | 61 + demo/proguard-rules.pro | 21 + .../android/demo/ExampleInstrumentedTest.kt | 24 + demo/src/main/AndroidManifest.xml | 34 + demo/src/main/assets/new_h5_test/README.md | 1 + demo/src/main/assets/new_h5_test/index.html | 310 ++ demo/src/main/assets/new_h5_test/index.js | 164 + .../assets/new_h5_test/sensorsdata.full.js | 4620 +++++++++++++++++ demo/src/main/assets/test.html | 114 + .../assets/visual_h5_test/definedemo.html | 148 + .../main/assets/visual_h5_test/defineindex.js | 50 + .../assets/visual_h5_test/sensorsdata.full.js | 4601 ++++++++++++++++ .../assets/visual_h5_test/vapph5define.js | 223 + .../analytics/android/demo/AAWebView.kt | 25 + .../analytics/android/demo/AWebView.kt | 28 + .../sensorsdata/analytics/android/demo/App.kt | 44 + .../analytics/android/demo/BaseActivity.kt | 68 + .../analytics/android/demo/ClickTest.java | 36 + .../analytics/android/demo/H5Activity.kt | 78 + .../analytics/android/demo/MainActivity.kt | 48 + .../drawable-v24/ic_launcher_foreground.xml | 30 + .../res/drawable/ic_launcher_background.xml | 170 + demo/src/main/res/layout/activity_h5.xml | 13 + demo/src/main/res/layout/activity_main.xml | 28 + .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + .../src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 1404 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 2898 bytes .../src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 982 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 1772 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 1900 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 3918 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 2884 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 5914 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 3844 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 7778 bytes demo/src/main/res/values-night/themes.xml | 16 + demo/src/main/res/values/colors.xml | 10 + demo/src/main/res/values/strings.xml | 3 + demo/src/main/res/values/themes.xml | 16 + demo/src/main/res/xml/backup_rules.xml | 13 + .../main/res/xml/data_extraction_rules.xml | 19 + .../analytics/android/demo/ExampleUnitTest.kt | 17 + ext.gradle | 19 - gradle.properties | 28 +- gradle/wrapper/gradle-wrapper.jar | Bin 53636 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 6 +- gradle_portal_plugin/.gitignore | 1 + gradle_portal_plugin/build.gradle | 12 + gradlew | 111 +- gradlew.bat | 53 +- plugin/bintray.gradle => maven.gradle | 64 +- maven_gradle_portal.gradle | 29 + plugin/.gitignore | 1 - plugin/build.gradle | 44 - plugin/ext.gradle | 20 - plugin/maven.gradle | 56 - plugin/proguard-rules.pro | 17 - .../android/plugin/ClassNameAnalytics.groovy | 63 - .../SensorsAnalyticsClassVisitor.groovy | 170 - .../plugin/SensorsAnalyticsExtension.groovy | 85 - .../plugin/SensorsAnalyticsHookConfig.groovy | 448 -- .../plugin/SensorsAnalyticsPlugin.groovy | 67 - .../plugin/SensorsAnalyticsTransform.groovy | 484 -- .../SensorsAnalyticsTransformHelper.groovy | 153 - .../plugin/SensorsAnalyticsUtil.groovy | 225 - .../plugin/configs/SAConfigHookHelper.java | 120 - .../configs/SensorsAnalyticsSDKExtension.java | 40 - .../SensorsAnalyticsSDKHookConfig.java | 168 - .../plugin/core/DefaultMethodVisitor.java | 27 - .../android/plugin/core/HookConstant.java | 10 - .../plugin/fragment/FragmentHookHelper.java | 42 - .../fragment/SensorsFragmentHookConfig.java | 61 - .../plugin/js/AddJSAnnotationVisitor.java | 41 - ...ensorsAnalyticsWebViewMethodVisitor.groovy | 200 - .../SensorsAnalyticsPushMethodVisitor.java | 133 - .../plugin/push/SensorsPushInjected.java | 210 - .../android/plugin/utils/LogUI.groovy | 58 - .../android/plugin/utils/Logger.groovy | 181 - .../android/plugin/utils/ModuleUtils.java | 30 - .../android/plugin/utils/TextUtil.java | 7 - .../android/plugin/utils/VersionUtils.java | 37 - .../SensorsAnalyticsVersionFieldVisitor.java | 67 - .../version/SensorsDataSDKVersionBean.java | 84 - .../version/SensorsDataSDKVersionHelper.java | 104 - .../viewclick/AutoTrackMethodVisitor.groovy | 153 - .../SensorsAnalyticsMethodCell.groovy | 96 - .../SensorsAutoTrackMethodVisitor.java | 693 --- ...m.sensorsdata.analytics.android.properties | 1 - publish.sh | 8 + sa-agp-api/.gitignore | 1 + sa-agp-api/build.gradle | 18 + .../analytics/android/gradle/AGP_Compat.kt | 14 + sa-agp-compat/.gitignore | 1 + sa-agp-compat/build.gradle | 15 + .../android/gradle/AGPCompatInterface.kt | 34 + .../analytics/android/gradle/AGPContext.kt | 30 + .../analytics/android/gradle/AGPVersion.kt | 67 + .../android/gradle/AsmCompatFactory.kt | 58 + .../analytics/android/gradle/ClassInfo.kt | 24 + .../analytics/android/gradle/CommonUtils.kt | 27 +- sa-agp-legacy/.gitignore | 1 + sa-agp-legacy/build.gradle | 18 + .../legacy/AGPLegacyClassInheritance.kt | 51 + .../gradle/legacy/AGPLegacyContextImpl.kt | 8 + .../android/gradle/legacy/AGPLegacyImpl.kt | 26 + .../gradle/legacy/AGPLegacyTransform.kt | 280 + .../android/gradle/legacy/BaseClassVisitor.kt | 6 + sa-agp-v7_3/.gitignore | 1 + sa-agp-v7_3/build.gradle | 15 + .../v7_3/SensorsDataAsmClassVisitorFactory.kt | 92 + .../android/gradle/v7_3/V73AGPContextImpl.kt | 9 + .../analytics/android/gradle/v7_3/V73Impl.kt | 66 + .../main/META-INF/sa-apg-compat.kotlin_module | Bin 0 -> 83 bytes .../android/gradle/AGPCompatInterface.class | Bin 0 -> 919 bytes .../analytics/android/gradle/AGPContext.class | Bin 0 -> 850 bytes .../AGPVersion$Companion$AGP_7_3_1$2.class | Bin 0 -> 1343 bytes ...sion$Companion$CURRENT_AGP_VERSION$2.class | Bin 0 -> 1647 bytes .../android/gradle/AGPVersion$Companion.class | Bin 0 -> 3764 bytes .../analytics/android/gradle/AGPVersion.class | Bin 0 -> 2954 bytes .../android/gradle/AsmCompatFactory.class | Bin 0 -> 1842 bytes .../analytics/android/gradle/ClassInfo.class | Bin 0 -> 4087 bytes .../android/gradle/ClassInheritance.class | Bin 0 -> 941 bytes .../android/gradle/CommonUtilsKt.class | Bin 0 -> 1674 bytes .../caches-jvm/inputs/source-to-output.tab | Bin 0 -> 4096 bytes .../inputs/source-to-output.tab.keystream | Bin 0 -> 4096 bytes .../inputs/source-to-output.tab.keystream.len | Bin 0 -> 8 bytes .../inputs/source-to-output.tab.len | Bin 0 -> 8 bytes .../inputs/source-to-output.tab.values.at | Bin 0 -> 1819 bytes .../caches-jvm/inputs/source-to-output.tab_i | Bin 0 -> 32768 bytes .../inputs/source-to-output.tab_i.len | Bin 0 -> 8 bytes .../jvm/kotlin/class-attributes.tab | Bin 0 -> 4096 bytes .../jvm/kotlin/class-attributes.tab.keystream | Bin 0 -> 4096 bytes .../kotlin/class-attributes.tab.keystream.len | Bin 0 -> 8 bytes .../jvm/kotlin/class-attributes.tab.len | Bin 0 -> 8 bytes .../jvm/kotlin/class-attributes.tab.values.at | Bin 0 -> 70 bytes .../jvm/kotlin/class-attributes.tab_i | Bin 0 -> 32768 bytes .../jvm/kotlin/class-attributes.tab_i.len | Bin 0 -> 8 bytes .../jvm/kotlin/class-fq-name-to-source.tab | Bin 0 -> 4096 bytes .../class-fq-name-to-source.tab.keystream | Bin 0 -> 4096 bytes .../class-fq-name-to-source.tab.keystream.len | Bin 0 -> 8 bytes .../kotlin/class-fq-name-to-source.tab.len | Bin 0 -> 8 bytes .../class-fq-name-to-source.tab.values.at | Bin 0 -> 769 bytes .../jvm/kotlin/class-fq-name-to-source.tab_i | Bin 0 -> 32768 bytes .../kotlin/class-fq-name-to-source.tab_i.len | Bin 0 -> 8 bytes .../jvm/kotlin/internal-name-to-source.tab | Bin 0 -> 4096 bytes .../internal-name-to-source.tab.keystream | Bin 0 -> 4096 bytes .../internal-name-to-source.tab.keystream.len | Bin 0 -> 8 bytes .../kotlin/internal-name-to-source.tab.len | Bin 0 -> 8 bytes .../internal-name-to-source.tab.values.at | Bin 0 -> 1073 bytes .../jvm/kotlin/internal-name-to-source.tab_i | Bin 0 -> 32768 bytes .../kotlin/internal-name-to-source.tab_i.len | Bin 0 -> 8 bytes .../caches-jvm/jvm/kotlin/package-parts.tab | Bin 0 -> 4096 bytes .../jvm/kotlin/package-parts.tab.keystream | Bin 0 -> 4096 bytes .../kotlin/package-parts.tab.keystream.len | Bin 0 -> 8 bytes .../jvm/kotlin/package-parts.tab.len | Bin 0 -> 8 bytes .../jvm/kotlin/package-parts.tab.values.at | Bin 0 -> 52 bytes .../caches-jvm/jvm/kotlin/package-parts.tab_i | Bin 0 -> 32768 bytes .../jvm/kotlin/package-parts.tab_i.len | Bin 0 -> 8 bytes .../cacheable/caches-jvm/jvm/kotlin/proto.tab | Bin 0 -> 4096 bytes .../caches-jvm/jvm/kotlin/proto.tab.keystream | Bin 0 -> 4096 bytes .../jvm/kotlin/proto.tab.keystream.len | Bin 0 -> 8 bytes .../caches-jvm/jvm/kotlin/proto.tab.len | Bin 0 -> 8 bytes .../caches-jvm/jvm/kotlin/proto.tab.values.at | Bin 0 -> 3677 bytes .../caches-jvm/jvm/kotlin/proto.tab_i | Bin 0 -> 32768 bytes .../caches-jvm/jvm/kotlin/proto.tab_i.len | Bin 0 -> 8 bytes .../jvm/kotlin/source-to-classes.tab | Bin 0 -> 4096 bytes .../kotlin/source-to-classes.tab.keystream | Bin 0 -> 4096 bytes .../source-to-classes.tab.keystream.len | Bin 0 -> 8 bytes .../jvm/kotlin/source-to-classes.tab.len | Bin 0 -> 8 bytes .../kotlin/source-to-classes.tab.values.at | Bin 0 -> 758 bytes .../jvm/kotlin/source-to-classes.tab_i | Bin 0 -> 32768 bytes .../jvm/kotlin/source-to-classes.tab_i.len | Bin 0 -> 8 bytes .../caches-jvm/jvm/kotlin/subtypes.tab | Bin 0 -> 4096 bytes .../jvm/kotlin/subtypes.tab.keystream | Bin 0 -> 4096 bytes .../jvm/kotlin/subtypes.tab.keystream.len | Bin 0 -> 8 bytes .../caches-jvm/jvm/kotlin/subtypes.tab.len | Bin 0 -> 8 bytes .../jvm/kotlin/subtypes.tab.values.at | Bin 0 -> 103 bytes .../caches-jvm/jvm/kotlin/subtypes.tab_i | Bin 0 -> 32768 bytes .../caches-jvm/jvm/kotlin/subtypes.tab_i.len | Bin 0 -> 8 bytes .../caches-jvm/jvm/kotlin/supertypes.tab | Bin 0 -> 4096 bytes .../jvm/kotlin/supertypes.tab.keystream | Bin 0 -> 4096 bytes .../jvm/kotlin/supertypes.tab.keystream.len | Bin 0 -> 8 bytes .../caches-jvm/jvm/kotlin/supertypes.tab.len | Bin 0 -> 8 bytes .../jvm/kotlin/supertypes.tab.values.at | Bin 0 -> 69 bytes .../caches-jvm/jvm/kotlin/supertypes.tab_i | Bin 0 -> 32768 bytes .../jvm/kotlin/supertypes.tab_i.len | Bin 0 -> 8 bytes .../cacheable/caches-jvm/lookups/counters.tab | 2 + .../caches-jvm/lookups/file-to-id.tab | Bin 0 -> 4096 bytes .../lookups/file-to-id.tab.keystream | Bin 0 -> 4096 bytes .../lookups/file-to-id.tab.keystream.len | Bin 0 -> 8 bytes .../caches-jvm/lookups/file-to-id.tab.len | Bin 0 -> 8 bytes .../lookups/file-to-id.tab.values.at | Bin 0 -> 85 bytes .../caches-jvm/lookups/file-to-id.tab_i | Bin 0 -> 32768 bytes .../caches-jvm/lookups/file-to-id.tab_i.len | Bin 0 -> 8 bytes .../caches-jvm/lookups/id-to-file.tab | Bin 0 -> 4096 bytes .../lookups/id-to-file.tab.keystream | Bin 0 -> 4096 bytes .../lookups/id-to-file.tab.keystream.len | Bin 0 -> 8 bytes .../caches-jvm/lookups/id-to-file.tab.len | Bin 0 -> 8 bytes .../lookups/id-to-file.tab.values.at | Bin 0 -> 669 bytes .../caches-jvm/lookups/id-to-file.tab_i | Bin 0 -> 32768 bytes .../caches-jvm/lookups/id-to-file.tab_i.len | Bin 0 -> 8 bytes .../cacheable/caches-jvm/lookups/lookups.tab | Bin 0 -> 4096 bytes .../caches-jvm/lookups/lookups.tab.keystream | Bin 0 -> 4096 bytes .../lookups/lookups.tab.keystream.len | Bin 0 -> 8 bytes .../caches-jvm/lookups/lookups.tab.len | Bin 0 -> 8 bytes .../caches-jvm/lookups/lookups.tab.values.at | Bin 0 -> 1727 bytes .../caches-jvm/lookups/lookups.tab_i | Bin 0 -> 32768 bytes .../caches-jvm/lookups/lookups.tab_i.len | Bin 0 -> 8 bytes .../compileKotlin/cacheable/last-build.bin | Bin 0 -> 18 bytes .../local-state/build-history.bin | Bin 0 -> 31 bytes .../kotlin/saapgcompat400betajar-classes.txt | 1 + .../libs/sa-apg-compat-4.0.0-beta-javadoc.jar | Bin 0 -> 261 bytes .../libs/sa-apg-compat-4.0.0-beta-sources.jar | Bin 0 -> 6054 bytes .../build/libs/sa-apg-compat-4.0.0-beta.jar | Bin 0 -> 12726 bytes .../publications/mavenAndroid/pom-default.xml | 41 + sa-apg-compat/build/tmp/jar/MANIFEST.MF | 2 + .../build/tmp/javadocJar/MANIFEST.MF | 2 + .../module-maven-metadata.xml | 13 + sa-apg-compat/build/tmp/sourceJar/MANIFEST.MF | 2 + sa-gradle-plugin/.gitignore | 1 + sa-gradle-plugin/build.gradle | 30 + .../android/plugin/AsmCompatFactoryImpl.kt | 55 + .../android/plugin/ClassNameAnalytics.kt | 41 + .../android/plugin/SensorsAnalyticsPlugin.kt | 12 + .../android/plugin/common/HookConstant.kt | 12 + .../android/plugin/common/VersionConstant.kt | 8 + .../plugin/configs/SAConfigHookHelper.kt | 128 + .../configs/SensorsAnalyticsHookConfig.kt | 604 +++ .../configs/SensorsAnalyticsSDKHookConfig.kt | 261 + .../android/plugin/extension/SAExtension.kt | 37 + .../plugin/extension/SASDKExtension.kt | 21 + .../plugin/fragment/FragmentHookHelper.kt | 50 + .../fragment/SensorsFragmentHookConfig.kt | 64 + .../plugin/js/AddJSAnnotationVisitor.kt | 29 + .../SensorsAnalyticsWebViewMethodVisitor.kt | 169 + .../plugin/manager/SAPackageManager.kt | 175 + .../android/plugin/manager/SAPluginManager.kt | 111 + .../push/SensorsAnalyticsPushMethodVisitor.kt | 154 + .../plugin/push/SensorsPushInjected.kt | 305 ++ .../analytics/android/plugin/utils/LogUI.kt | 13 + .../analytics/android/plugin/utils/Logger.kt | 69 + .../analytics/android/plugin/utils/SAUtils.kt | 102 + .../android/plugin/utils/TextUtil.kt | 7 + .../SensorsAnalyticsVersionFieldVisitor.kt | 69 + .../version/SensorsDataSDKVersionBean.kt | 79 + .../version/SensorsDataSDKVersionHelper.kt | 101 + .../SensorsAutoTrackMethodVisitor.kt | 831 +++ .../plugin/visitor/SAPrimaryClassVisitor.kt | 172 + .../visitor/SensorsAnalyticsJSRAdapter.kt | 14 + .../visitor/SensorsAnalyticsMethodCell.kt | 76 + .../visitor/UpdateSDKPluginVersionMV.kt | 25 + ...m.sensorsdata.analytics.android.properties | 18 + screenshots/android_sdk_autotrack_1.png | Bin 385685 -> 0 bytes screenshots/android_sdk_autotrack_2.png | Bin 501602 -> 0 bytes screenshots/android_sdk_autotrack_4.png | Bin 243610 -> 0 bytes screenshots/android_sdk_autotrack_5.png | Bin 449745 -> 0 bytes settings.gradle | 30 +- 260 files changed, 16049 insertions(+), 4566 deletions(-) create mode 100644 demo/.gitignore create mode 100644 demo/build.gradle create mode 100644 demo/proguard-rules.pro create mode 100644 demo/src/androidTest/java/com/sensorsdata/analytics/android/demo/ExampleInstrumentedTest.kt create mode 100644 demo/src/main/AndroidManifest.xml create mode 100644 demo/src/main/assets/new_h5_test/README.md create mode 100644 demo/src/main/assets/new_h5_test/index.html create mode 100644 demo/src/main/assets/new_h5_test/index.js create mode 100644 demo/src/main/assets/new_h5_test/sensorsdata.full.js create mode 100644 demo/src/main/assets/test.html create mode 100755 demo/src/main/assets/visual_h5_test/definedemo.html create mode 100755 demo/src/main/assets/visual_h5_test/defineindex.js create mode 100755 demo/src/main/assets/visual_h5_test/sensorsdata.full.js create mode 100755 demo/src/main/assets/visual_h5_test/vapph5define.js create mode 100644 demo/src/main/java/com/sensorsdata/analytics/android/demo/AAWebView.kt create mode 100644 demo/src/main/java/com/sensorsdata/analytics/android/demo/AWebView.kt create mode 100644 demo/src/main/java/com/sensorsdata/analytics/android/demo/App.kt create mode 100644 demo/src/main/java/com/sensorsdata/analytics/android/demo/BaseActivity.kt create mode 100644 demo/src/main/java/com/sensorsdata/analytics/android/demo/ClickTest.java create mode 100644 demo/src/main/java/com/sensorsdata/analytics/android/demo/H5Activity.kt create mode 100644 demo/src/main/java/com/sensorsdata/analytics/android/demo/MainActivity.kt create mode 100644 demo/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 demo/src/main/res/drawable/ic_launcher_background.xml create mode 100644 demo/src/main/res/layout/activity_h5.xml create mode 100644 demo/src/main/res/layout/activity_main.xml create mode 100644 demo/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 demo/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 demo/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 demo/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 demo/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 demo/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 demo/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 demo/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 demo/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 demo/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 demo/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 demo/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 demo/src/main/res/values-night/themes.xml create mode 100644 demo/src/main/res/values/colors.xml create mode 100644 demo/src/main/res/values/strings.xml create mode 100644 demo/src/main/res/values/themes.xml create mode 100644 demo/src/main/res/xml/backup_rules.xml create mode 100644 demo/src/main/res/xml/data_extraction_rules.xml create mode 100644 demo/src/test/java/com/sensorsdata/analytics/android/demo/ExampleUnitTest.kt delete mode 100755 ext.gradle create mode 100644 gradle_portal_plugin/.gitignore create mode 100644 gradle_portal_plugin/build.gradle rename plugin/bintray.gradle => maven.gradle (62%) mode change 100755 => 100644 create mode 100644 maven_gradle_portal.gradle delete mode 100644 plugin/.gitignore delete mode 100755 plugin/build.gradle delete mode 100755 plugin/ext.gradle delete mode 100755 plugin/maven.gradle delete mode 100644 plugin/proguard-rules.pro delete mode 100755 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/ClassNameAnalytics.groovy delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/SensorsAnalyticsClassVisitor.groovy delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/SensorsAnalyticsExtension.groovy delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/SensorsAnalyticsHookConfig.groovy delete mode 100755 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/SensorsAnalyticsPlugin.groovy delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/SensorsAnalyticsTransform.groovy delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/SensorsAnalyticsTransformHelper.groovy delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/SensorsAnalyticsUtil.groovy delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/configs/SAConfigHookHelper.java delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/configs/SensorsAnalyticsSDKExtension.java delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/configs/SensorsAnalyticsSDKHookConfig.java delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/core/DefaultMethodVisitor.java delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/core/HookConstant.java delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/fragment/FragmentHookHelper.java delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/fragment/SensorsFragmentHookConfig.java delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/js/AddJSAnnotationVisitor.java delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/js/SensorsAnalyticsWebViewMethodVisitor.groovy delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/push/SensorsAnalyticsPushMethodVisitor.java delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/push/SensorsPushInjected.java delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/utils/LogUI.groovy delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/utils/Logger.groovy delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/utils/ModuleUtils.java delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/utils/TextUtil.java delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/utils/VersionUtils.java delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/version/SensorsAnalyticsVersionFieldVisitor.java delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/version/SensorsDataSDKVersionBean.java delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/version/SensorsDataSDKVersionHelper.java delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/viewclick/AutoTrackMethodVisitor.groovy delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/viewclick/SensorsAnalyticsMethodCell.groovy delete mode 100644 plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/viewclick/SensorsAutoTrackMethodVisitor.java delete mode 100755 plugin/src/main/resources/META-INF/gradle-plugins/com.sensorsdata.analytics.android.properties create mode 100755 publish.sh create mode 100644 sa-agp-api/.gitignore create mode 100644 sa-agp-api/build.gradle create mode 100644 sa-agp-api/src/main/kotlin/com/sensorsdata/analytics/android/gradle/AGP_Compat.kt create mode 100644 sa-agp-compat/.gitignore create mode 100644 sa-agp-compat/build.gradle create mode 100644 sa-agp-compat/src/main/kotlin/com/sensorsdata/analytics/android/gradle/AGPCompatInterface.kt create mode 100644 sa-agp-compat/src/main/kotlin/com/sensorsdata/analytics/android/gradle/AGPContext.kt create mode 100644 sa-agp-compat/src/main/kotlin/com/sensorsdata/analytics/android/gradle/AGPVersion.kt create mode 100644 sa-agp-compat/src/main/kotlin/com/sensorsdata/analytics/android/gradle/AsmCompatFactory.kt create mode 100644 sa-agp-compat/src/main/kotlin/com/sensorsdata/analytics/android/gradle/ClassInfo.kt rename plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/SensorsAnalyticsJSRAdapter.java => sa-agp-compat/src/main/kotlin/com/sensorsdata/analytics/android/gradle/CommonUtils.kt (57%) create mode 100644 sa-agp-legacy/.gitignore create mode 100644 sa-agp-legacy/build.gradle create mode 100644 sa-agp-legacy/src/main/kotlin/com/sensorsdata/analytics/android/gradle/legacy/AGPLegacyClassInheritance.kt create mode 100644 sa-agp-legacy/src/main/kotlin/com/sensorsdata/analytics/android/gradle/legacy/AGPLegacyContextImpl.kt create mode 100644 sa-agp-legacy/src/main/kotlin/com/sensorsdata/analytics/android/gradle/legacy/AGPLegacyImpl.kt create mode 100644 sa-agp-legacy/src/main/kotlin/com/sensorsdata/analytics/android/gradle/legacy/AGPLegacyTransform.kt create mode 100644 sa-agp-legacy/src/main/kotlin/com/sensorsdata/analytics/android/gradle/legacy/BaseClassVisitor.kt create mode 100644 sa-agp-v7_3/.gitignore create mode 100644 sa-agp-v7_3/build.gradle create mode 100644 sa-agp-v7_3/src/main/kotlin/com/sensorsdata/analytics/android/gradle/v7_3/SensorsDataAsmClassVisitorFactory.kt create mode 100644 sa-agp-v7_3/src/main/kotlin/com/sensorsdata/analytics/android/gradle/v7_3/V73AGPContextImpl.kt create mode 100644 sa-agp-v7_3/src/main/kotlin/com/sensorsdata/analytics/android/gradle/v7_3/V73Impl.kt create mode 100644 sa-apg-compat/build/classes/kotlin/main/META-INF/sa-apg-compat.kotlin_module create mode 100644 sa-apg-compat/build/classes/kotlin/main/com/sensorsdata/analytics/android/gradle/AGPCompatInterface.class create mode 100644 sa-apg-compat/build/classes/kotlin/main/com/sensorsdata/analytics/android/gradle/AGPContext.class create mode 100644 sa-apg-compat/build/classes/kotlin/main/com/sensorsdata/analytics/android/gradle/AGPVersion$Companion$AGP_7_3_1$2.class create mode 100644 sa-apg-compat/build/classes/kotlin/main/com/sensorsdata/analytics/android/gradle/AGPVersion$Companion$CURRENT_AGP_VERSION$2.class create mode 100644 sa-apg-compat/build/classes/kotlin/main/com/sensorsdata/analytics/android/gradle/AGPVersion$Companion.class create mode 100644 sa-apg-compat/build/classes/kotlin/main/com/sensorsdata/analytics/android/gradle/AGPVersion.class create mode 100644 sa-apg-compat/build/classes/kotlin/main/com/sensorsdata/analytics/android/gradle/AsmCompatFactory.class create mode 100644 sa-apg-compat/build/classes/kotlin/main/com/sensorsdata/analytics/android/gradle/ClassInfo.class create mode 100644 sa-apg-compat/build/classes/kotlin/main/com/sensorsdata/analytics/android/gradle/ClassInheritance.class create mode 100644 sa-apg-compat/build/classes/kotlin/main/com/sensorsdata/analytics/android/gradle/CommonUtilsKt.class create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/inputs/source-to-output.tab create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.keystream create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.keystream.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.values.at create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab_i create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab_i.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/lookups/counters.tab create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/lookups/file-to-id.tab create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/lookups/id-to-file.tab create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/lookups/lookups.tab create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/lookups/lookups.tab.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/lookups/lookups.tab_i create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/caches-jvm/lookups/lookups.tab_i.len create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/cacheable/last-build.bin create mode 100644 sa-apg-compat/build/kotlin/compileKotlin/local-state/build-history.bin create mode 100644 sa-apg-compat/build/kotlin/saapgcompat400betajar-classes.txt create mode 100644 sa-apg-compat/build/libs/sa-apg-compat-4.0.0-beta-javadoc.jar create mode 100644 sa-apg-compat/build/libs/sa-apg-compat-4.0.0-beta-sources.jar create mode 100644 sa-apg-compat/build/libs/sa-apg-compat-4.0.0-beta.jar create mode 100644 sa-apg-compat/build/publications/mavenAndroid/pom-default.xml create mode 100644 sa-apg-compat/build/tmp/jar/MANIFEST.MF create mode 100644 sa-apg-compat/build/tmp/javadocJar/MANIFEST.MF create mode 100644 sa-apg-compat/build/tmp/publishMavenAndroidPublicationToMavenRepository/module-maven-metadata.xml create mode 100644 sa-apg-compat/build/tmp/sourceJar/MANIFEST.MF create mode 100644 sa-gradle-plugin/.gitignore create mode 100644 sa-gradle-plugin/build.gradle create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/AsmCompatFactoryImpl.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/ClassNameAnalytics.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/SensorsAnalyticsPlugin.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/common/HookConstant.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/common/VersionConstant.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/configs/SAConfigHookHelper.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/configs/SensorsAnalyticsHookConfig.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/configs/SensorsAnalyticsSDKHookConfig.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/extension/SAExtension.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/extension/SASDKExtension.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/fragment/FragmentHookHelper.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/fragment/SensorsFragmentHookConfig.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/js/AddJSAnnotationVisitor.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/js/SensorsAnalyticsWebViewMethodVisitor.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/manager/SAPackageManager.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/manager/SAPluginManager.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/push/SensorsAnalyticsPushMethodVisitor.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/push/SensorsPushInjected.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/utils/LogUI.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/utils/Logger.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/utils/SAUtils.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/utils/TextUtil.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/version/SensorsAnalyticsVersionFieldVisitor.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/version/SensorsDataSDKVersionBean.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/version/SensorsDataSDKVersionHelper.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/viewclick/SensorsAutoTrackMethodVisitor.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/visitor/SAPrimaryClassVisitor.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/visitor/SensorsAnalyticsJSRAdapter.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/visitor/SensorsAnalyticsMethodCell.kt create mode 100644 sa-gradle-plugin/src/main/kotlin/com/sensorsdata/analytics/android/plugin/visitor/UpdateSDKPluginVersionMV.kt create mode 100644 sa-gradle-plugin/src/main/resources/META-INF/gradle-plugins/com.sensorsdata.analytics.android.properties delete mode 100644 screenshots/android_sdk_autotrack_1.png delete mode 100644 screenshots/android_sdk_autotrack_2.png delete mode 100644 screenshots/android_sdk_autotrack_4.png delete mode 100644 screenshots/android_sdk_autotrack_5.png diff --git a/build.gradle b/build.gradle index 7ee2c7b..ea24d1f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,37 +1,15 @@ -apply from: 'ext.gradle' - -buildscript { - repositories { - google() - mavenLocal() - mavenCentral() - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:3.4.1' - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + id 'com.android.application' version '7.3.1' apply false //demo used + id 'com.android.library' version '7.3.1' apply false //demo used + id 'org.jetbrains.kotlin.android' version '1.7.20' apply false + id 'org.jetbrains.kotlin.jvm' version '1.7.20' apply false + id 'com.gradle.plugin-publish' version '1.1.0' apply false +// id 'com.sensorsdata.analytics.android' version '4.0.0-beta' apply false } -allprojects { - buildscript { - repositories { - mavenLocal() - mavenCentral() - jcenter() - } - } - dependencies { - repositories { - google() - mavenLocal() - mavenCentral() - jcenter() - } - } - - apply plugin: 'maven' -} +ext { + agpVersion = '7.3.1' //used for compile + pluginVersion = '4.0.0-beta' //plugin version +} \ No newline at end of file diff --git a/demo/.gitignore b/demo/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/demo/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/demo/build.gradle b/demo/build.gradle new file mode 100644 index 0000000..5693cee --- /dev/null +++ b/demo/build.gradle @@ -0,0 +1,61 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' +// id 'com.sensorsdata.analytics.android' +} + +android { + namespace 'com.sensorsdata.analytics.android.demo' + compileSdk 32 + + defaultConfig { + applicationId "com.sensorsdata.analytics.android.demo" + minSdk 28 + targetSdk 32 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } +} + +dependencies { + + implementation 'androidx.core:core-ktx:1.7.0' + implementation 'androidx.appcompat:appcompat:1.4.1' + implementation 'com.google.android.material:material:1.5.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.3' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + implementation('com.sensorsdata.analytics.android:SensorsAnalyticsSDK:6.6.0') +} + +//sensorsAnalytics { +// debug = true +// disableModules = ['PUSH'] +// // exclude=['com.sensorsdata.analytics.android.demo'] +//// disableTrackPush = true +//// sdk{ +//// disableAndroidID = true +//// disableIMEI=true +//// disableMacAddress=true +//// disableCarrier=true +//// disableOAID=false +//// } +//// addUCJavaScriptInterface=true +//} \ No newline at end of file diff --git a/demo/proguard-rules.pro b/demo/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/demo/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/demo/src/androidTest/java/com/sensorsdata/analytics/android/demo/ExampleInstrumentedTest.kt b/demo/src/androidTest/java/com/sensorsdata/analytics/android/demo/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..a3f3922 --- /dev/null +++ b/demo/src/androidTest/java/com/sensorsdata/analytics/android/demo/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.sensorsdata.analytics.android.demo + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.sensorsdata.analytics.android.plugin", appContext.packageName) + } +} \ No newline at end of file diff --git a/demo/src/main/AndroidManifest.xml b/demo/src/main/AndroidManifest.xml new file mode 100644 index 0000000..d08d9d4 --- /dev/null +++ b/demo/src/main/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/src/main/assets/new_h5_test/README.md b/demo/src/main/assets/new_h5_test/README.md new file mode 100644 index 0000000..b9a562d --- /dev/null +++ b/demo/src/main/assets/new_h5_test/README.md @@ -0,0 +1 @@ +# App_H5_traffic_sdk \ No newline at end of file diff --git a/demo/src/main/assets/new_h5_test/index.html b/demo/src/main/assets/new_h5_test/index.html new file mode 100644 index 0000000..77d711f --- /dev/null +++ b/demo/src/main/assets/new_h5_test/index.html @@ -0,0 +1,310 @@ + + + + + + + + + sdk demo ls + + + + + +
+ + + + + +
+ + +
点击输入text:提交:
+ + 跳转页面demo +
+
+ + +
+
+

iframe indexdemo

+ +
+
+ + + + + +
+
+
+ + + + +
+ +
+ +
+
+ +
+
+ +
+
+
+ turn to p3 +
+
+ +
+ +
+
...
+
+ +
+
+
+ +
+
+ + + + +
+ + + + + + + + \ No newline at end of file diff --git a/demo/src/main/assets/new_h5_test/index.js b/demo/src/main/assets/new_h5_test/index.js new file mode 100644 index 0000000..87e0232 --- /dev/null +++ b/demo/src/main/assets/new_h5_test/index.js @@ -0,0 +1,164 @@ +(function (para) { + var p = para.sdk_url, + n = para.name, + w = window, + d = document, + s = 'script', + x = null, + y = null; + if (typeof (w['sensorsDataAnalytic201505']) !== 'undefined') { + return false; + } + w['sensorsDataAnalytic201505'] = n; //'sensors' + w[n] = w[n] || function (a) { + return function () { + (w[n]._q = w[n]._q || []).push([a, arguments]); + } + }; + var ifs = ['track', 'quick', 'register', 'registerPage', 'registerOnce', 'trackSignup', 'trackAbtest', 'setProfile', 'setOnceProfile', 'appendProfile', 'incrementProfile', 'deleteProfile', 'unsetProfile', 'identify', 'login', 'logout', 'trackLink', 'clearAllRegister', 'getAppStatus']; + for (var i = 0; i < ifs.length; i++) { + w[n][ifs[i]] = w[n].call(null, ifs[i]); + } + // var obtn = document.getElementById('test'); + // console.log(obtn); + // obtn.onclick = function(){ + // x = d.createElement(s), y = d.getElementsByTagName(s)[0]; + // x.async = 1; + // x.src = p; + // x.setAttribute('charset','UTF-8'); + // w[n].para = para; + // y.parentNode.insertBefore(x, y); + // }; + if (!w[n]._t) { + x = d.createElement(s), y = d.getElementsByTagName(s)[0]; + x.async = 1; + x.src = p; + x.setAttribute('charset', 'UTF-8'); + w[n].para = para; + y.parentNode.insertBefore(x, y); + } +})({ + sdk_url:'./sensorsdata.full.js', + // sdk_url: 'https://869359954.github.io/sadefine/sensorsdata.full.js', + // sdk_url:'https://cdn.jsdelivr.net/npm/sa-sdk-javascript@1.14.20/sensorsdata.min.js', + // heatmap_url: 'https://cdn.jsdelivr.net/npm/sa-sdk-javascript@1.14.21/heatmap.min.js', + // sdk_url: './sdk-919/sensorsdata.full.js', + // heatmap_url: './sensors/heatmap.js', + name: 'sensors', + is_track_device_id: true, + source_channel: ['bd_vid'], + source_type: { + search: ['.baidu.com', '.google.', 'ecosia.org'], + social: ['.kaixin001.com'] + }, + // server_url:'', + server_url: 'https://sdkdebugtest.datasink.sensorsdata.cn/sa?project=default&token=cfb8b60e42e0ae9b', + // server_url: ['https://test-syg.datasink.sensorsdata.cn/sa?project=liangshuang&token=27f1e21b78daf376','https://test-syg.datasink.sensorsdata.cn/sa?project=lixiang&token=27f1e21b78daf376'], + debug_mode: false, + debug_mode_upload: false, + // send_type:'ajax', + // use_app_track: true, + use_app_track_config:{ + use_app_track:true, + white_list:['https://sdkdebugtest.datasink.sensorsdata.cn/sa?project=default&token=cfb8b60e42e0ae9b', + 'http://test-syg.datasink.sensorsdata.cn/sa?project=liangshuang&token=27f1e21b78daf376', + 'https://newsdktest.datasink.sensorsdata.cn/sa?project=zhangwei&token=5a394d2405c147ca'] + }, + use_client_time: true, + cross_subdomain: false, + // batch_send:{ + // datasend_timeout: 6000, //一次请求超过多少秒的话自动取消,防止请求无响应。 + // send_interval: 12000, //间隔几秒发一次数据。 + // one_send_max_length: 6 //一次请求最大发送几条数据,防止数据太大 + // }, + is_track_single_page: false, + // heatmap:{}, + heatmap: { + // clickmap:'not_collect', + // scroll_notice_map:'not_collect', + loadTimeout: 3000, + // collect_url: function(){ + // //如果只采集首页 + // if(location.href === 'http://www.ls.com:8080/index.html'){ + // return false; + // }else{ + // return true; + // } + // }, + collect_element: function (element_target) { + // 如果这个元素有属性sensors-disable=true时候,不采集 + if (element_target.getAttribute('sensors-disable') === 'true') { + return false; + } else { + return true; + } + }, + custom_property: function (element_target) { + return { + timepppp: new Date() + } + }, + collect_input: function (element_target) { + //例如如果元素的 id 是a,就采集这个元素里的内容 + // if(element_target.id === 'loginid'){ + // return true; + // } + return true; + }, + // element_selector:'not_use_id', + renderRefreshTime: 1000, + scroll_delay_time: 4000, + useCapture: false + }, + // preset_properties:{ + // title:false + // } +}); +// sensors.registerPage({ +// $title : '123tt' +// }); + +// sensors.quick('autoTrackWithoutProfile'); +sensors.quick('autoTrack', { + $title: 'mytest' +}); +sensors.track('sdk_1152', {}); +// sensors.quick('isReady',function(){ +// var pro = sensors.getPresetProperties(); +// console.log(pro); +// }) +// sensors.setProfile() +// window.SensorsData_APP_JS_Bridge = { +// sensorsdata_define_mode : function(data){ +// // var data = JSON.parse(data); +// console.log(data); + +// } +// }; + +// var webkit = { +// messageHandlers :{ +// sensorsdataNativeTracker : { +// postMessage : function(data){ +// console.log('ios 成功接收数据'); +// console.log(data); +// } +// } +// } +// }; +// var SensorsData_iOS_JS_Bridge = { +// sensorsdata_app_server_url: 'http://test-syg.datasink.sensorsdata.cn/sa?project=liangshuang&token=27f1e21b78daf376', +// }; + +// var SensorsData_APP_JS_Bridge = { +// // sensorsdata_track : function(data){ +// // console.log('android接收数据',data); +// // }, +// // sensorsdata_get_server_url:function(){ +// // return 'https://test-syg.datasink.sensorsdata.cn/sa?project=liangshuang&token=27f1e21b78daf376'; +// // } +// // sensorsdata_verify:function(data){ +// // console.log('android verify 接收数据',data); +// // return true; +// // } +// }; diff --git a/demo/src/main/assets/new_h5_test/sensorsdata.full.js b/demo/src/main/assets/new_h5_test/sensorsdata.full.js new file mode 100644 index 0000000..f29f1ca --- /dev/null +++ b/demo/src/main/assets/new_h5_test/sensorsdata.full.js @@ -0,0 +1,4620 @@ +/* +sdk的初始化和组织 +*/ + +/** + * @fileoverview sensors analytic javascript sdk + * @author shengyonggen@sensorsdata.cn + * 神策数据 www.sensorsdata.cn ,长期招聘 前端SDK开发工程师 ,简历求发送到我邮箱,谢谢 + */ + +;(function(factory) { + if (typeof exports === 'object' && typeof module === 'object') { + module.exports = factory(); + } else{ + factory(); + } +})(function(){ + +try{ + + + +var sd = {}; + +var _ = sd._ = {}; + +// 压缩后的json库,照抄的github上的库 +if(typeof JSON!=='object'){JSON={}}(function(){'use strict';var rx_one=/^[\],:{}\s]*$/,rx_two=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,rx_three=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,rx_four=/(?:^|:|,)(?:\s*\[)+/g,rx_escapable=/[\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,rx_dangerous=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;function f(n){return n<10?'0'+n:n}function this_value(){return this.valueOf()}if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+'-'+f(this.getUTCMonth()+1)+'-'+f(this.getUTCDate())+'T'+f(this.getUTCHours())+':'+f(this.getUTCMinutes())+':'+f(this.getUTCSeconds())+'Z':null};Boolean.prototype.toJSON=this_value;Number.prototype.toJSON=this_value;String.prototype.toJSON=this_value}var gap,indent,meta,rep;function quote(string){rx_escapable.lastIndex=0;return rx_escapable.test(string)?'"'+string.replace(rx_escapable,function(a){var c=meta[a];return typeof c==='string'?c:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==='object'&&typeof value.toJSON==='function'){value=value.toJSON(key)}if(typeof rep==='function'){value=rep.call(holder,key,value)}switch(typeof value){case'string':return quote(value);case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null'}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==='[object Array]'){length=value.length;for(i=0;i '未取到值' +// * Opera 15 on macOS +// * Firefox 68 on macOS +// * Safari 12.1 on macOS +// * Chrome 75 on macOS +// * Safari on iPhone X +// * Chrome on Google Pixel 2 +_.getScreenOrientation = function() { + // Screen Orientation API + var screenOrientationAPI = screen.msOrientation || screen.mozOrientation || (screen.orientation || {}).type; + var screenOrientation = '未取到值'; + if (screenOrientationAPI) { + screenOrientation = screenOrientationAPI.indexOf('landscape') > -1 ? 'landscape' : 'portrait'; + } else if (_.mediaQueriesSupported()) { // matchMedia + var matchMediaFunc = window.matchMedia || window.msMatchMedia; + if (matchMediaFunc("(orientation: landscape)").matches) { + screenOrientation = 'landscape'; + } else if (matchMediaFunc("(orientation: portrait)").matches) { + screenOrientation = 'portrait'; + } + } + return screenOrientation; +}; + +_.now = Date.now || function() { + return new Date().getTime(); +}; + +_.throttle = function(func, wait, options) { + var context, args, result; + var timeout = null; + var previous = 0; + if (!options) options = {}; + var later = function() { + previous = options.leading === false ? 0 : _.now(); + timeout = null; + result = func.apply(context, args); + if (!timeout) context = args = null; + }; + return function() { + var now = _.now(); + if (!previous && options.leading === false) previous = now; + var remaining = wait - (now - previous); + context = this; + args = arguments; + if (remaining <= 0 || remaining > wait) { + if (timeout) { + clearTimeout(timeout); + timeout = null; + } + previous = now; + result = func.apply(context, args); + if (!timeout) context = args = null; + } else if (!timeout && options.trailing !== false) { + timeout = setTimeout(later, remaining); + } + return result; + }; +}; + +_.hashCode = function(str){ + if(typeof str !== 'string'){ + return 0; + } + var hash = 0; + var char = null; + if (str.length == 0) { + return hash; + } + for (var i = 0; i < str.length; i++) { + char = str.charCodeAt(i); + hash = ((hash<<5)-hash)+char; + hash = hash & hash; + } + return hash; +}; + +_.formatDate = function(d) { + function pad(n) { + return n < 10 ? '0' + n : n; + } + + return d.getFullYear() + '-' + + pad(d.getMonth() + 1) + '-' + + pad(d.getDate()) + ' ' + + pad(d.getHours()) + ':' + + pad(d.getMinutes()) + ':' + + pad(d.getSeconds()) + '.' + + pad(d.getMilliseconds()); +}; + +// 把日期格式全部转化成日期字符串 +_.searchObjDate = function(o) { + if (_.isObject(o)) { + _.each(o, function(a, b) { + if (_.isObject(a)) { + _.searchObjDate(o[b]); + } else { + if (_.isDate(a)) { + o[b] = _.formatDate(a); + } + } + }); + } +}; + +_.searchZZAppStyle = function(data){ + if(typeof data.properties.$project !== 'undefined'){ + data.project = data.properties.$project; + delete data.properties.$project; + } + if(typeof data.properties.$token !== 'undefined'){ + data.token = data.properties.$token; + delete data.properties.$token; + } +}; + +_.formatJsonString = function(obj){ + try{ + return JSON.stringify(obj, null, ' '); + }catch(e){ + return JSON.stringify(obj); + } +}; + +// 把字符串格式数据限制字符串长度 +_.formatString = function(str) { + if (str.length > sd.para.max_string_length) { + sd.log('字符串长度超过限制,已经做截取--' + str); + return str.slice(0, sd.para.max_string_length); + } else { + return str; + } +}; + +// 把字符串格式数据限制字符串长度 +_.searchObjString = function(o) { + if (_.isObject(o)) { + _.each(o, function(a, b) { + if (_.isObject(a)) { + _.searchObjString(o[b]); + } else { + if (_.isString(a)) { + o[b] = _.formatString(a); + } + } + }); + } +}; + +/** + * 执行属性中的函数,并且过滤掉不符合条件的属性 + * + * @param {Object} obj - Properties. + * + */ +_.parseSuperProperties = function(obj) { + if (_.isObject(obj)) { + _.each(obj, function(value, key) { + if (_.isFunction(value)) { + try { + obj[key] = value(); + if (_.isFunction(obj[key])) { + sd.log("您的属性- " + key + ' 格式不满足要求,我们已经将其删除'); + delete obj[key]; + } + } catch (e) { + delete obj[key]; + sd.log("您的属性- " + key + ' 抛出了异常,我们已经将其删除'); + } + } + }); + _.strip_sa_properties(obj); + } +}; + + +/** + * @description 过滤掉事件的属性名为保留字段的属性 + * @param {object} obj 属性对象 + */ +_.filterReservedProperties = function(obj){ + var reservedFields =['distinct_id','user_id','id','date','datetime','event','events','first_id','original_id','device_id','properties','second_id','time','users']; + if(!_.isObject(obj)){ + return; + } + _.each(reservedFields, function(key,index){ + if(!(key in obj)){ + return; + } + if(index < 3){ + delete obj[key]; + sd.log("您的属性- " + key + '是保留字段,我们已经将其删除') + }else{ + sd.log("您的属性- " + key + '是保留字段,请避免其作为属性名') + } + }); +} + +// 去除$option的配置数据 +_.searchConfigData = function(data){ + if(typeof data === 'object' && data.$option){ + var data_config = data.$option; + delete data.$option; + return data_config; + }else{ + return {}; + } +} + + +// 数组去重复 +_.unique = function(ar) { + var temp, n = [], o = {}; + for (var i = 0; i < ar.length; i++) { + temp = ar[i]; + if (!(temp in o)) { + o[temp] = true; + n.push(temp); + } + } + return n; +}; + +// 只能是sensors满足的数据格式 +_.strip_sa_properties = function(p) { + if (!_.isObject(p)) { + return p; + } + _.each(p, function(v, k) { + // 如果是数组,把值自动转换成string + if (_.isArray(v)) { + var temp = []; + _.each(v, function(arrv) { + if (_.isString(arrv)) { + temp.push(arrv); + } else { + sd.log('您的数据-',k, v, '的数组里的值必须是字符串,已经将其删除'); + } + }); + if (temp.length !== 0) { + p[k] = temp; + } else { + delete p[k]; + sd.log('已经删除空的数组'); + } + } + // 只能是字符串,数字,日期,布尔,数组 + if (!(_.isString(v) || _.isNumber(v) || _.isDate(v) || _.isBoolean(v) || _.isArray(v) || _.isFunction(v) || (k === '$option'))) { + sd.log('您的数据-',k, v, '-格式不满足要求,我们已经将其删除'); + delete p[k]; + } + }); + return p; +}; + +// 去掉undefined和null +_.strip_empty_properties = function(p) { + var ret = {}; + _.each(p, function(v, k) { + if (v != null) { + ret[k] = v; + } + }); + return ret; +}; + +_.utf8Encode = function(string) { + string = (string + '').replace(/\r\n/g, '\n').replace(/\r/g, '\n'); + + var utftext = '', start, end; + var stringl = 0, n; + + start = end = 0; + stringl = string.length; + + for (n = 0; n < stringl; n++) { + var c1 = string.charCodeAt(n); + var enc = null; + + if (c1 < 128) { + end++; + } else if ((c1 > 127) && (c1 < 2048)) { + enc = String.fromCharCode((c1 >> 6) | 192, (c1 & 63) | 128); + } else { + enc = String.fromCharCode((c1 >> 12) | 224, ((c1 >> 6) & 63) | 128, (c1 & 63) | 128); + } + if (enc !== null) { + if (end > start) { + utftext += string.substring(start, end); + } + utftext += enc; + start = end = n + 1; + } + } + + if (end > start) { + utftext += string.substring(start, string.length); + } + + return utftext; +}; + +/** + * Create a base-64 encoded ASCII string from a UTF-8 string. + */ +_.base64Encode = function(data) { + if (typeof btoa === 'function') { + return btoa(encodeURIComponent(data).replace(/%([0-9A-F]{2})/g, function (match, p1) { + return String.fromCharCode('0x' + p1); + })); + } + data = String(data); + var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, enc = '', tmp_arr = []; + if (!data) { + return data; + } + data = _.utf8Encode(data); + do { + o1 = data.charCodeAt(i++); + o2 = data.charCodeAt(i++); + o3 = data.charCodeAt(i++); + + bits = o1 << 16 | o2 << 8 | o3; + + h1 = bits >> 18 & 0x3f; + h2 = bits >> 12 & 0x3f; + h3 = bits >> 6 & 0x3f; + h4 = bits & 0x3f; + tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4); + } while (i < data.length); + + enc = tmp_arr.join(''); + + switch (data.length % 3) { + case 1: + enc = enc.slice(0, -2) + '=='; + break; + case 2: + enc = enc.slice(0, -1) + '='; + break; + } + + return enc; +}; + + +_.UUID = (function() { + var T = function() { + var d = 1 * new Date(), i = 0; + while (d == 1 * new Date()) { + i++; + } + return d.toString(16) + i.toString(16); + }; + var R = function() { + return Math.random().toString(16).replace('.', ''); + }; + var UA = function(n) { + var ua = navigator.userAgent, i, ch, buffer = [], ret = 0; + + function xor(result, byte_array) { + var j, tmp = 0; + for (j = 0; j < byte_array.length; j++) { + tmp |= (buffer[j] << j * 8); + } + return result ^ tmp; + } + + for (i = 0; i < ua.length; i++) { + ch = ua.charCodeAt(i); + buffer.unshift(ch & 0xFF); + if (buffer.length >= 4) { + ret = xor(ret, buffer); + buffer = []; + } + } + + if (buffer.length > 0) { + ret = xor(ret, buffer); + } + + return ret.toString(16); + }; + + return function() { + // 有些浏览器取个屏幕宽度都异常... + var se = String(screen.height * screen.width); + if (se && /\d{5,}/.test(se)) { + se = se.toString(16); + } else { + se = String(Math.random() * 31242).replace('.', '').slice(0, 8); + } + var val = (T() + '-' + R() + '-' + UA() + '-' + se + '-' + T()); + if(val){ + return val; + }else{ + return (String(Math.random()) + String(Math.random()) + String(Math.random())).slice(2, 15); + } + + }; +})(); + + +_.getQueryParam = function(url, param) { + param = param.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]"); + url = _.decodeURIComponent(url); + var regexS = "[\\?&]" + param + "=([^&#]*)", + regex = new RegExp(regexS), + results = regex.exec(url); + if (results === null || (results && typeof(results[1]) !== 'string' && results[1].length)) { + return ''; + } else { + return _.decodeURIComponent(results[1]); + } +}; + +_.urlParse = function(para) { + var URLParser = function(a) { + this._fields = { + Username: 4, + Password: 5, + Port: 7, + Protocol: 2, + Host: 6, + Path: 8, + URL: 0, + QueryString: 9, + Fragment: 10 + }; + this._values = {}; + this._regex = null; + this._regex = /^((\w+):\/\/)?((\w+):?(\w+)?@)?([^\/\?:]+):?(\d+)?(\/?[^\?#]+)?\??([^#]+)?#?(\w*)/; + + if (typeof a != 'undefined') { + this._parse(a) + } + }; + URLParser.prototype.setUrl = function(a) { + this._parse(a) + }; + URLParser.prototype._initValues = function() { + for (var a in this._fields) { + this._values[a] = '' + } + }; + URLParser.prototype.addQueryString = function(queryObj) { + if(typeof queryObj !== 'object'){ + return false; + } + var query = this._values.QueryString || ''; + for(var i in queryObj){ + if(new RegExp(i+'[^&]+').test(query)){ + query = query.replace(new RegExp(i+'[^&]+'), i + '=' + queryObj[i]); + }else{ + if(query.slice(-1) === '&'){ + query = query + i + '=' + queryObj[i]; + }else{ + if(query === ''){ + query = i + '=' + queryObj[i]; + }else{ + query = query + '&' + i + '=' + queryObj[i]; + } + } + } + } + this._values.QueryString = query; + }; + URLParser.prototype.getUrl = function() { + var url = ''; + url += this._values.Origin; + url += this._values.Port ? ':' + this._values.Port : ''; + url += this._values.Path; + url += this._values.QueryString ? '?' + this._values.QueryString : ''; + url += this._values.Fragment ? '#'+this._values.Fragment : ''; + return url; + }; + + URLParser.prototype.getUrl = function() { + var url = ''; + url += this._values.Origin; + url += this._values.Port ? ':' + this._values.Port : ''; + url += this._values.Path; + url += this._values.QueryString ? '?' + this._values.QueryString : ''; + return url; + }; + URLParser.prototype._parse = function(a) { + this._initValues(); + var b = this._regex.exec(a); + if (!b) { + throw 'DPURLParser::_parse -> Invalid URL' + } + for (var c in this._fields) { + if (typeof b[this._fields[c]] != 'undefined') { + this._values[c] = b[this._fields[c]] + } + } + this._values['Hostname'] = this._values['Host'].replace(/:\d+$/, ''); + this._values['Origin'] = this._values['Protocol'] + '://' + this._values['Hostname']; + + }; + return new URLParser(para); +}; + +/* ulr预置 +_.referringDomain = function(referrer) { + var split = referrer.split('/'); + if (split.length >= 3) { + return split[2]; + } + return ''; +}; + +_.getDomainByHost = function(url) { + if (typeof url === 'string' && url.split('.').length >= 2) { + var temp = url.match(/[^\.]+\.[^.]+$/); + if (temp && temp[0]) { + return temp[0]; + } else { + return ''; + } + } else { + return ''; + } +} +*/ + +/* _.draggable = function(elementToDrag, event) { + function getScrollOffsets() { + var w = document; + if (w.pageXOffset != null) { + return { + x: w.pageXOffset, + y: w.pageYOffset + }; + } else { + return { + x: w.documentElement.scrollLeft, + y: w.documentElement.scrollTop + }; + } + } + + var scroll = getScrollOffsets(); + var startX = event.clientX + scroll.x; + var startY = event.clientY + scroll.y; + var origX = elementToDrag.offsetLeft; + var origY = elementToDrag.offsetTop; + var deltaX = startX - origX; + var deltaY = startY - origY; + if (document.addEventListener) { + document.addEventListener("mousemove", moveHandler); + document.addEventListener("mouseup", upHandler); + } else if (document.attachEvent) { + document.attachEvent("onmousemove", moveHandler); + document.attachEvent("onmouseup", upHandler); + } + if (event.stopPropagation) event.stopPropagation(); + else event.cancelBubble = true; + if (event.preventDefault) event.preventDefault(); + else event.returnValue = false; + + elementToDrag.style.bottom = 'auto'; + + function moveHandler(e) { + e = e || window.event; + var scroll = getScrollOffsets(); + elementToDrag.style.left = (e.clientX + scroll.x - deltaX) + "px"; + elementToDrag.style.top = (e.clientY + scroll.y - deltaY) + "px"; + if (e.stopPropagation) e.stopPropagation(); + else e.cancelBubble = true; + } + function upHandler(e) { + if (!e) e = window.event; + if (document.removeEventListener) { + document.removeEventListener("mouseup", upHandler); + document.removeEventListener("mousemove", moveHandler); + } else if (document.detachEvent) { + document.detachEvent("onmouseup", upHandler); + document.detachEvent("onmousemove", moveHandler); + } + if (e.stopPropagation) e.stopPropagation(); + else e.cancelBubble = true; + } +} */ + +// 是否有标准的浏览器环境,如果不是发送$errorEnviroment:{$errorReson:'没有window'} +/* _.hasStandardBrowserEnviroment = function() { + if (!window) { + return 'window'; + } + if (!document) { + return 'document'; + } + if (!navigator) { + return 'navigator'; + } + if (!screen) { + return 'screen'; + } + +}; */ + +/* _.bindReady = function(fn,win) { + win = win || window; + var done = false, + top = true, + doc = win.document, + root = doc.documentElement, + modern = doc.addEventListener, + add = modern ? 'addEventListener' : 'attachEvent', + rem = modern ? 'removeEventListener' : 'detachEvent', + pre = modern ? '' : 'on', + init = function(e) { + if (e.type == 'readystatechange' && doc.readyState != 'complete') return; + (e.type == 'load' ? win : doc)[rem](pre + e.type, init, false); + if (!done && (done = true)) fn.call(win, e.type || e); + }, + poll = function() { + try { root.doScroll('left'); } catch(e) { setTimeout(poll, 50); return; } + init('poll'); + }; + + if (doc.readyState == 'complete') fn.call(win, 'lazy'); + else { + if (!modern && root.doScroll) { + try { top = !win.frameElement; } catch(e) { } + if (top) poll(); + } + doc[add](pre + 'DOMContentLoaded', init, false); + doc[add](pre + 'readystatechange', init, false); + win[add](pre + 'load', init, false); + } + +}; */ + + +_.addEvent = function() { + + function fixEvent(event) { + if (event) { + event.preventDefault = fixEvent.preventDefault; + event.stopPropagation = fixEvent.stopPropagation; + event._getPath = fixEvent._getPath; + } + return event; + } + fixEvent._getPath = function(){ + var ev = this; + var polyfill = function () { + try{ + var element = ev.target; + var pathArr = [element]; + if (element === null || element.parentElement === null) { + return []; + } + while (element.parentElement !== null) { + element = element.parentElement; + pathArr.unshift(element); + } + return pathArr; + }catch(err){ + return []; + } + + }; + return this.path || (this.composedPath && this.composedPath()) || polyfill(); + }; + fixEvent.preventDefault = function() { + this.returnValue = false; + }; + fixEvent.stopPropagation = function() { + this.cancelBubble = true; + }; + + + var register_event = function(element, type, handler) { + var useCapture = _.isObject(sd.para.heatmap) && sd.para.heatmap.useCapture ? true : false; + if (element && element.addEventListener) { + element.addEventListener(type, function(e){ + e._getPath = fixEvent._getPath; + handler.call(this,e); + }, useCapture); + } else { + var ontype = 'on' + type; + var old_handler = element[ontype]; + element[ontype] = makeHandler(element, handler, old_handler); + } + }; + function makeHandler(element, new_handler, old_handlers) { + var handler = function(event) { + event = event || fixEvent(window.event); + if (!event) { + return undefined; + } + event.target = event.srcElement; + + var ret = true; + var old_result, new_result; + if (typeof old_handlers === 'function') { + old_result = old_handlers(event); + } + new_result = new_handler.call(element, event); + if ((false === old_result) || (false === new_result)) { + ret = false; + } + return ret; + }; + return handler; + } + + register_event.apply(null,arguments); +}; + + +_.addHashEvent = function(callback){ + var hashEvent = ('pushState' in window.history ? 'popstate' : 'hashchange'); + _.addEvent(window,hashEvent,callback); +}; + +_.addSinglePageEvent = function(callback){ + var current_url = location.href; + var historyPushState = window.history.pushState; + var historyReplaceState = window.history.replaceState; + + //调用方法导致的url切换 + window.history.pushState = function () { + historyPushState.apply(window.history, arguments); + callback(current_url); + current_url = location.href; + }; + window.history.replaceState = function () { + historyReplaceState.apply(window.history,arguments); + callback(current_url); + current_url = location.href; + }; + + // 前进后退导致的url切换 + var singlePageEvent = historyPushState ? 'popstate' : 'hashchange'; + _.addEvent(window,singlePageEvent,function(){ + callback(current_url); + current_url = location.href; + }); +}; + +_.cookie = { + get: function(name) { + var nameEQ = name + '='; + var ca = document.cookie.split(';'); + for (var i = 0; i < ca.length; i++) { + var c = ca[i]; + while (c.charAt(0) == ' ') { + c = c.substring(1, c.length); + } + if (c.indexOf(nameEQ) == 0) { + return _.decodeURIComponent(c.substring(nameEQ.length, c.length)); + } + } + return null; + }, + set: function(name, value, days, cross_subdomain, is_secure) { + cross_subdomain = typeof cross_subdomain === 'undefined' ? sd.para.cross_subdomain : cross_subdomain; + var cdomain = '', expires = '', secure = ''; + days = days == null ? 73000 : days; + + if (cross_subdomain) { + var domain = _.getCurrentDomain(location.href); + if(domain === 'url解析失败'){ + domain = ''; + } + cdomain = ((domain) ? '; domain=' + domain : ''); + } + + // 0 session + // -1 马上过期 + // + if (days !== 0) { + var date = new Date(); + // 默认是天,可以是秒 + if (String(days).slice(-1) === 's') { + date.setTime(date.getTime() + (Number(String(days).slice(0, -1)) * 1000)); + } else { + date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); + } + + expires = '; expires=' + date.toGMTString(); + } + + if (is_secure) { + secure = '; secure'; + } + + document.cookie = name + '=' + encodeURIComponent(value) + expires + + '; path=/' + cdomain + secure; + }, + + remove: function(name, cross_subdomain) { + cross_subdomain = typeof cross_subdomain === 'undefined' ? sd.para.cross_subdomain : cross_subdomain; + _.cookie.set(name, '', -1, cross_subdomain); + + }, + + getCookieName: function(name_prefix, url){ + var sub = ''; + url = url || location.href; + if(sd.para.cross_subdomain === false){ + try { + sub = _.URL(url).hostname; + } catch (e) { + // do nothing + } + if(typeof sub === 'string' && sub !== ''){ + sub = 'sajssdk_2015_' + name_prefix + '_' + sub.replace(/\./g, '_'); + }else{ + sub = 'sajssdk_2015_root_' + name_prefix; + } + }else{ + sub = 'sajssdk_2015_cross_' + name_prefix; + } + return sub; + }, +// 针对新用户的兼容性判断,兼容子域名 + getNewUser: function(){ + var prefix = 'new_user'; + if(this.get('sensorsdata_is_new_user') !== null || this.get(this.getCookieName(prefix)) !== null){ + return true; + }else{ + return false; + } + } +}; + +// 获取元素的一些信息 +_.getEleInfo = function(obj){ + if(!obj.target){ + return false; + } + + var target = obj.target; + var tagName = target.tagName.toLowerCase(); + + + var props = {}; + + props.$element_type = tagName; + props.$element_name = target.getAttribute('name'); + props.$element_id = target.getAttribute('id'); + props.$element_class_name = typeof target.className === 'string' ? target.className : null; + props.$element_target_url = target.getAttribute('href'); + + // 获取内容 + + var textContent = ''; + if (target.textContent) { + textContent = _.trim(target.textContent); + }else if(target.innerText){ + textContent = _.trim(target.innerText); + } + if (textContent) { + textContent = textContent.replace(/[\r\n]/g, ' ').replace(/[ ]+/g, ' ').substring(0, 255); + } + props.$element_content = textContent || ''; + + // 针对inut默认只采集button和submit非名感的词汇。可以自定义(银联提) + if(tagName === 'input'){ + if(target.type === 'button' || target.type === 'submit'){ + props.$element_content = target.value || ''; + } else if (sd.para.heatmap && (typeof sd.para.heatmap.collect_input === 'function') && sd.para.heatmap.collect_input(target)){ + props.$element_content = target.value || ''; + } + } + + props = _.strip_empty_properties(props); + + props.$url = location.href; + props.$url_path = location.pathname; + props.$title = document.title; + props.$viewport_width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth || 0; + + return props; + +}; + +// _.localStorage +_.localStorage = { + get: function(name) { + return window.localStorage.getItem(name); + }, + + parse: function(name) { + var storedValue; + try { + storedValue = JSON.parse(_.localStorage.get(name)) || null; + } catch (err) { + } + return storedValue; + }, + + set: function(name, value) { + window.localStorage.setItem(name, value); + }, + + remove: function(name) { + window.localStorage.removeItem(name); + }, + + isSupport: function() { + var supported = true; + try { + var key = '__sensorsdatasupport__'; + var val = 'testIsSupportStorage'; + _.localStorage.set(key, val); + if (_.localStorage.get(key) !== val) { + supported = false; + } + _.localStorage.remove(key); + } catch (err) { + supported = false; + } + return supported; + } + +}; + +_.sessionStorage = { + + isSupport:function(){ + var supported = true; + + var key = '__sensorsdatasupport__'; + var val = 'testIsSupportStorage'; + try{ + if(sessionStorage && sessionStorage.setItem){ + sessionStorage.setItem(key,val); + sessionStorage.removeItem(key,val); + supported = true; + }else{ + supported = false; + } + }catch(e){ + supported = false; + } + return supported; + } +}; + +// 检测是否支持跨域的ajax发送 +_.isSupportCors = function () { + if (typeof window.XMLHttpRequest === 'undefined') { + return false; + } + //Detect browser support for CORS + if ('withCredentials' in new XMLHttpRequest()) { + /* supports cross-domain requests */ + return true; + } else if(typeof XDomainRequest !== "undefined"){ + //Use IE-specific "CORS" code with XDR + return true; + } else { + //Time to retreat with a fallback or polyfill + return false; + } +}; + +_.xhr = function(cors) { + if (cors) { + if (typeof window.XMLHttpRequest !== 'undefined' && ("withCredentials" in new XMLHttpRequest())) { + return new XMLHttpRequest(); + } else if (typeof XDomainRequest !== "undefined") { + return new XDomainRequest(); + } else { + return null; + } + } else { + if (typeof window.XMLHttpRequest !== 'undefined') { + return new XMLHttpRequest(); + } + if (window.ActiveXObject) { + try { + return new ActiveXObject('Msxml2.XMLHTTP') + } catch (d) { + try { + return new ActiveXObject('Microsoft.XMLHTTP') + } catch (d) { + } + } + } + } +}; + + +_.ajax = function(para) { + para.timeout = para.timeout || 20000; + + para.credentials = (typeof para.credentials) === 'undefined' ? true : para.credentials; + function getJSON(data) { + if(!data){ + return ''; + } + try { + return JSON.parse(data); + } catch (e) { + return {}; + } + } + + var g = _.xhr(para.cors); + + if(!g) { + return false; + } + + if (!para.type) { + para.type = para.data ? 'POST' : 'GET'; + } + para = _.extend({ + success: function() {}, + error: function() {} + }, para); + + try{ + if(typeof g === 'object' && ('timeout' in g)){ + g.timeout = para.timeout; + }else{ + setTimeout(function(){ + g.abort(); + },para.timeout+500); + } + }catch(e){ + try{ + setTimeout(function(){ + g.abort(); + },para.timeout+500); + }catch(e2){}; + }; + + g.onreadystatechange = function() { + try{ + if (g.readyState == 4) { + if ((g.status >= 200 && g.status < 300) || g.status == 304) { + para.success(getJSON(g.responseText)); + } else { + para.error(getJSON(g.responseText), g.status); + } + g.onreadystatechange = null; + g.onload = null; + } + }catch(e){ + g.onreadystatechange = null; + g.onload = null; + }; + + }; + + g.open(para.type, para.url, true); + + try { + if(para.credentials){ + g.withCredentials = true; + } + if (_.isObject(para.header)) { + for (var i in para.header) { + g.setRequestHeader(i, para.header[i]); + } + } + + if (para.data) { + if(!para.cors){ + g.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + } + if (para.contentType === 'application/json') { + g.setRequestHeader("Content-type", "application/json; charset=UTF-8"); + } else { + g.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); + } + + } + } catch (e) {}; + + g.send(para.data || null); + +}; + + _.loadScript = function(para) { + para = _.extend({ + success: function() {}, + error: function() {}, + appendCall: function(g) { + document.getElementsByTagName('head')[0].appendChild(g); + } + }, para); + + var g = null; + if (para.type === 'css') { + g = document.createElement('link'); + g.rel = 'stylesheet'; + g.href = para.url; + } + if (para.type === 'js') { + g = document.createElement('script'); + g.async = 'async'; + g.setAttribute('charset','UTF-8'); + g.src = para.url; + g.type = 'text/javascript'; + } + g.onload = g.onreadystatechange = function() { + if (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') { + para.success(); + g.onload = g.onreadystatechange = null; + } + }; + g.onerror = function() { + para.error(); + g.onerror = null; + }; + // if iframe + para.appendCall(g); +}; + +_.getHostname = function(url, defaultValue) { + if (!defaultValue || typeof defaultValue !== "string") { + defaultValue = "hostname解析异常"; + } + var hostname = null; + try { + hostname = _.URL(url).hostname; + } catch (e) { + // do nothing + } + return hostname || defaultValue; +}; + +_.getQueryParamsFromUrl = function(url) { + var result = {}; + var arr = url.split('?'); + var queryString = arr[1] || ''; + if (queryString) { + result = _.getURLSearchParams('?' + queryString); + } + return result; +}; + +/** + * 查询得到URL参数 + * @param {string} queryString - 以问号开头的 query string + * @return {Object} 一个含有参数列表的key/value对象 + * + * @example + * var url = _.getURLSearchParams('?project=testproject&query1=test&silly=willy&field[0]=zero&field[2]=two#test=hash&chucky=cheese'); + * + * url.project; // => testproject + */ +_.getURLSearchParams = function(queryString) { + queryString = queryString || ""; + var decodeParam = function(str) { + return decodeURIComponent(str); + }; + var args = {}; // Start with an empty object + var query = queryString.substring(1); // Get query string, minus '?' + var pairs = query.split("&"); // Split at ampersands + for(var i = 0; i < pairs.length; i++) { // For each fragment + var pos = pairs[i].indexOf('='); // Look for "name=value" + if (pos === -1) continue; // If not found, skip it + var name = pairs[i].substring(0,pos); // Extract the name + var value = pairs[i].substring(pos+1); // Extract the value + name = decodeParam(name); // Decode the name + value = decodeParam(value); // Decode the value + args[name] = value; // Store as a property + } + return args; // Return the parsed arguments +}; + +/** + * 解析URL + * @param {string} url + * @return {Object} 一个 URL 对象或者普通JS对象 + * + * @example + * var url = _.URL('http://www.domain.com:8080/path/index.html?project=testproject&query1=test&silly=willy&field[0]=zero&field[2]=two#test=hash&chucky=cheese'); + * + * url.hostname; // => www.domain.com + * url.searchParams.get('project'); // => testproject + */ +_.URL = function(url) { + var result = {}; + var basicProps = ['hash', 'host', 'hostname', 'href', 'origin', 'password', 'pathname', 'port', 'protocol', 'search', 'username']; + // Some browsers allow objects to be created via URL constructor, but instances do not have the expected url properties. + // See https://www.caniuse.com/#feat=url + var isURLAPIWorking = function() { + var url; + try { + url = new URL('http://modernizr.com/'); + return url.href === 'http://modernizr.com/'; + } catch (e) { + return false; + } + }; + if (typeof window.URL === 'function' && isURLAPIWorking()) { + result = new URL(url); + if (!result.searchParams) { + result.searchParams = (function(){ + var params = _.getURLSearchParams(result.search); + return { + get: function(searchParam) { + return params[searchParam]; + } + }; + })(); + } + } else { + var _regex = /^https?:\/\/.+/; + if(_regex.test(url) === false) { + throw 'Invalid URL'; + } + var link = document.createElement('a'); + link.href = url; + for (var i = basicProps.length - 1; i >= 0; i--) { + var prop = basicProps[i]; + result[prop] = link[prop]; + } + if (result.hostname && typeof result.pathname === "string" && result.pathname.indexOf('/') !== 0) { + result.pathname = '/' + result.pathname; + } + result.searchParams = (function(){ + var params = _.getURLSearchParams(result.search); + return { + get: function(searchParam) { + return params[searchParam]; + } + }; + })(); + } + return result; +}; + +_.getCurrentDomain = function (url) { + var sdDomain = sd.para.current_domain; + switch (typeof (sdDomain)) { + case "function": + var resultDomain = sdDomain(); + if (resultDomain === "" || _.trim(resultDomain) === "") { + return 'url解析失败'; + } else if (resultDomain.indexOf(".")!== -1) { + return resultDomain; + } else { + return "url解析失败"; + } + case "string": + if (sdDomain === "" || _.trim(sdDomain) === "") { + return 'url解析失败'; + } else if (sdDomain.indexOf(".")!== -1) { + return sdDomain; + } else { + return "url解析失败"; + } + default: + var cookieTopLevelDomain = _.getCookieTopLevelDomain(); + if (url === '') { + return 'url解析失败'; + } else if (cookieTopLevelDomain === '') { + return 'url解析失败'; + } else { + return cookieTopLevelDomain; + } + } +}; + +_.getCookieTopLevelDomain = function(hostname) { + hostname = hostname || window.location.hostname; + /* + if (hostname === 'localhost') { + return hostname; + } + */ + var splitResult = hostname.split('.'); + if (_.isArray(splitResult) && splitResult.length >= 2 && !/^(\d+\.)+\d+$/.test(hostname)) { + var domainStr = '.' + splitResult.splice(splitResult.length - 1, 1); + while (splitResult.length > 0) { + domainStr = '.' + splitResult.splice(splitResult.length - 1, 1) + domainStr; + document.cookie = "sensorsdata_domain_test=true; path=/; domain=" + domainStr; + if (document.cookie.indexOf('sensorsdata_domain_test=true') !== -1) { + var now = new Date(); + now.setTime(now.getTime() - 1000); + document.cookie = "sensorsdata_domain_test=true; expires=" + now.toGMTString() + "; path=/; domain=" + domainStr; + return domainStr; + } + } + } + return ''; +}; + +_.isReferralTraffic = function(refererstring) { + refererstring = refererstring || document.referrer; + if (refererstring === "") { + return true; + } + + return _.getCookieTopLevelDomain(_.getHostname(refererstring)) !== _.getCookieTopLevelDomain(); +}; + + +_.ry = function(dom){ + return new _.ry.init(dom); +}; +_.ry.init = function(dom){ + this.ele = dom; +}; +_.ry.init.prototype = { + addClass: function(para){ + var classes = ' ' + this.ele.className + ' '; + if(classes.indexOf(' ' + para + ' ') === -1){ + this.ele.className = this.ele.className + (this.ele.className === '' ? '' : ' ') + para; + } + return this; + }, + removeClass: function(para){ + var classes = ' ' + this.ele.className + ' '; + if(classes.indexOf(' ' + para + ' ') !== -1){ + this.ele.className = classes.replace(' ' + para + ' ', ' ').slice(1,-1); + } + return this; + }, + hasClass: function(para){ + var classes = ' ' + this.ele.className + ' '; + if(classes.indexOf(' ' + para + ' ') !== -1){ + return true; + }else{ + return false; + } + }, + attr: function(key,value){ + if(typeof key === 'string' && _.isUndefined(value)){ + return this.ele.getAttribute(key); + } + if(typeof key === 'string'){ + value = String(value); + this.ele.setAttribute(key,value); + } + return this; + }, + offset: function(){ + var rect = this.ele.getBoundingClientRect(); + if ( rect.width || rect.height ) { + var doc = this.ele.ownerDocument; + var docElem = doc.documentElement; + + return { + top: rect.top + window.pageYOffset - docElem.clientTop, + left: rect.left + window.pageXOffset - docElem.clientLeft + }; + }else{ + return { + top: 0, + left: 0 + } + } + + }, + getSize: function(){ + if (!window.getComputedStyle) { + return {width: this.ele.offsetWidth, height: this.ele.offsetHeight}; + } + try { + var bounds = this.ele.getBoundingClientRect(); + return {width: bounds.width, height: bounds.height}; + } catch (e){ + return {width: 0, height: 0}; + } + }, + getStyle: function(value){ + if(this.ele.currentStyle){ + return this.ele.currentStyle[value]; + }else{ + return this.ele.ownerDocument.defaultView.getComputedStyle(this.ele, null).getPropertyValue(value); + } + }, + wrap: function(elementTagName){ + var ele = document.createElement(elementTagName); + this.ele.parentNode.insertBefore(ele, this.ele); + ele.appendChild(this.ele); + return _.ry(ele); + }, + getCssStyle: function(prop){ + var result = this.ele.style.getPropertyValue(prop); + if (result) { + return result; + } + var rules = null; + if(typeof window.getMatchedCSSRules === 'function'){ + rules = getMatchedCSSRules(this.ele); + } + if(!rules || !_.isArray(rules)){ + return null; + } + for (var i = rules.length - 1; i >= 0; i--) { + var r = rules[i]; + result = r.style.getPropertyValue(prop); + if (result) { + return result; + } + } + }, + sibling:function(cur, dir ){ + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; + }, + next: function() { + return this.sibling( this.ele, "nextSibling" ); + }, + prev: function( elem ) { + return this.sibling( this.ele, "previousSibling" ); + }, + siblings: function( elem ) { + return this.siblings( ( this.ele.parentNode || {} ).firstChild, this.ele); + }, + children: function( elem ) { + return this.siblings( this.ele.firstChild ); + }, + parent: function(){ + var parent = this.ele.parentNode; + parent = parent && parent.nodeType !== 11 ? parent : null; + return _.ry(parent); + } +}; + +_.strToUnicode = function(str){ + if(typeof str !== 'string'){ + sd.log('转换unicode错误',str); + return str; + } + var nstr = ''; + for(var i = 0; i 0) { + campaign_keywords = campaign_keywords.concat(sd.para.source_channel); + campaign_keywords = _.unique(campaign_keywords); + } + _.each(campaign_keywords, function(kwkey) { + kw = _.getQueryParam(location.href, kwkey); + if (kw.length) { + params[kwkey] = kw; + } + }); + + return params; + }, + campaignParamsStandard: function(prefix,prefix_add) { + prefix = prefix || ''; + prefix_add = prefix_add || ''; + var utms = _.info.campaignParams(); + var $utms = {}, otherUtms = {}; + for (var i in utms) { + if ((' ' + sd.source_channel_standard + ' ').indexOf(' ' + i + ' ') !== -1) { + $utms[prefix + i] = utms[i]; + } else { + otherUtms[prefix_add + i] = utms[i]; + } + } + return { + $utms: $utms, + otherUtms: otherUtms + }; + }, + // 预置属性 + properties: function() { + return { + $screen_height: Number(screen.height) || 0, + $screen_width: Number(screen.width) || 0, + // 我说两遍写的重复,佳捷说就写两遍 + $lib: 'js', + $lib_version: String(sd.lib_version) + }; + }, + // 保存临时的一些变量,只针对当前页面有效 + currentProps: {}, + register: function(obj) { + _.extend(_.info.currentProps, obj); + } +}; + + + + +// 发送队列 +_.autoExeQueue = function(){ + var queue = { + // 简单队列 + items : [], + enqueue: function(val){ + this.items.push(val); + this.start(); + }, + dequeue: function(){ + return this.items.shift(); + }, + getCurrentItem: function(){ + return this.items[0]; + }, + // 自动循环执行队列 + isRun: false, + start: function(){ + if(this.items.length > 0 && !this.isRun){ + this.isRun = true; + this.getCurrentItem().start(); + } + }, + close: function(){ + this.dequeue(); + this.isRun = false; + this.start(); + } + }; + return queue; +}; + + + + _.trackLink = function(obj,event_name,event_prop){ + obj = obj || {}; + var link = null; + if(obj.ele){ + link = obj.ele; + } + if(obj.event){ + if(obj.target){ + link = obj.target; + }else{ + link = obj.event.target; + } + } + + event_prop = event_prop || {}; + if(!link || (typeof link !== 'object')){ + return false; + } + // 如果是非当前页面会跳转的链接,直接track + if (!link.href || /^javascript/.test(link.href) || link.target || link.download || link.onclick) { + sd.track(event_name, event_prop); + return false; + } + function linkFunc(e){ + e.stopPropagation(); + e.preventDefault(); // 阻止默认跳转 + var hasCalled = false; + function track_a_click(){ + if (!hasCalled) { + hasCalled = true; + location.href = link.href; //把 A 链接的点击跳转,改成 location 的方式跳转 + } + } + setTimeout(track_a_click, 1000); //如果没有回调成功,设置超时回调 + sd.track(event_name, event_prop, track_a_click); //把跳转操作加在callback里 + } + if(obj.event){ + linkFunc(obj.event); + } + if(obj.ele){ + _.addEvent(obj.ele,'click',function(e){ + linkFunc(e); + }); + } + }; + + + + +})(); + + +/* +sd的各个方法,包含sdk的一些基本功能 +*/ + + + sd.para_default = { + preset_properties: { + latest_utm: true, + latest_traffic_source_type: true, + latest_search_keyword: true, + latest_referrer: true, + latest_referrer_host: false, + latest_landing_page: false, + url: false, + title: false + }, + img_use_crossorigin: false, + //scrollmap:{delay:6000} + + name: 'sa', + // referrer字符串截取 + max_referrer_string_length: 200, + //通用字符串截取,超过7000的字符串会导致url超长发不出去,所以限制长度 + max_string_length: 500, + // send_error_event: true, + cross_subdomain: true, + show_log: true, + is_debug: false, + debug_mode: false, + debug_mode_upload: false, + + // todo 前端session时长 + session_time: 0, + + use_client_time: false, + //来源参数名字 + source_channel: [], + + send_type: 'image', + + // 七鱼过滤id + vtrack_ignore: {}, + + auto_init: true, + + is_track_single_page: false, + + is_single_page: false, + + batch_send: false, + + // 如果要设置,设置数组 + source_type: {}, + callback_timeout: 200, + datasend_timeout: 3000, + queue_timeout: 300, + is_track_device_id: false, + use_app_track_config:{ + use_app_track: false, + use_app_track_is_send: true, + white_list:[], + H5verify:false + }, + ignore_oom: true + }; + +sd.addReferrerHost = function(data) { + var defaultHost = "取值异常"; + if (_.isObject(data.properties)) { + if (data.properties.$first_referrer) { + data.properties.$first_referrer_host = _.getHostname(data.properties.$first_referrer, defaultHost); + } + if (data.type === "track") { + if ('$referrer' in data.properties) { + data.properties.$referrer_host = data.properties.$referrer === "" ? "" : _.getHostname(data.properties.$referrer, defaultHost); + } + if (sd.para.preset_properties.latest_referrer && sd.para.preset_properties.latest_referrer_host) { + data.properties.$latest_referrer_host = data.properties.$latest_referrer === "" ? "" : _.getHostname(data.properties.$latest_referrer, defaultHost); + } + } + } +}; + +sd.addPropsHook = function(data) { + if (sd.para.preset_properties && sd.para.preset_properties.url && data.type === "track" && typeof data.properties.$url === 'undefined') { + data.properties.$url = window.location.href; + } + if (sd.para.preset_properties && sd.para.preset_properties.title && data.type === "track" && typeof data.properties.$title === 'undefined') { + data.properties.$title = document.title; + } +}; + +sd.initPara = function(para){ + // 默认配置 + sd.para = para || sd.para || {}; + var latestObj = {}; + if(_.isObject(sd.para.is_track_latest)){ + for (var latestProp in sd.para.is_track_latest) { + latestObj['latest_' + latestProp] = sd.para.is_track_latest[latestProp]; + } + } + + sd.para.preset_properties = _.extend({}, sd.para_default.preset_properties, latestObj, sd.para.preset_properties || {}); + var app_track_config = {}; + if(sd.para.use_app_track){ + app_track_config.use_app_track = sd.para.use_app_track; + } + if(sd.para.use_app_track_is_send){ + app_track_config.use_app_track_is_send = sd.para.use_app_track_is_send; + } + sd.para.use_app_track_config = _.extend({},sd.para_default.use_app_track_config,app_track_config,sd.para.use_app_track_config || {}) + + var i; + // 合并配置 + for (i in sd.para_default) { + if (sd.para[i] === void 0) { + sd.para[i] = sd.para_default[i]; + } + } + // 修复没有配置协议的问题,自动取当前页面的协议 + if(typeof sd.para.server_url === 'string' && sd.para.server_url.slice(0,3) === '://'){ + sd.para.server_url = location.protocol + sd.para.server_url; + } + if(typeof sd.para.web_url === 'string' && sd.para.web_url.slice(0,3) === '://'){ + sd.para.web_url = location.protocol + sd.para.web_url; + } + + if(sd.para.send_type !== 'image' && sd.para.send_type !== 'ajax' && sd.para.send_type !== 'beacon'){ + sd.para.send_type = 'image'; + } + + var batch_send_default = { + datasend_timeout: 6000, + send_interval: 6000, + one_send_max_length: 6 + }; + + if(_.localStorage.isSupport() && _.isSupportCors() && typeof localStorage === 'object'){ + if (sd.para.batch_send === true) { + sd.para.batch_send = _.extend({}, batch_send_default); + sd.para.use_client_time = true; + }else if(typeof sd.para.batch_send === 'object'){ + sd.para.use_client_time = true; + sd.para.batch_send = _.extend({}, batch_send_default, sd.para.batch_send); + } + }else{ + sd.para.batch_send = false; + } + + + var utm_type = ['utm_source','utm_medium','utm_campaign','utm_content','utm_term']; + var search_type = ['www.baidu.','m.baidu.','m.sm.cn','so.com','sogou.com','youdao.com','google.','yahoo.com/','bing.com/','ask.com/']; + var social_type = ['weibo.com','renren.com','kaixin001.com','douban.com','qzone.qq.com','zhihu.com','tieba.baidu.com','weixin.qq.com']; + var search_keyword = {baidu:['wd','word','kw','keyword'],google:'q',bing:'q',yahoo:'p',sogou:['query','keyword'],so:'q',sm:'q'}; + + if(typeof sd.para.source_type === 'object'){ + sd.para.source_type.utm = _.isArray(sd.para.source_type.utm) ? sd.para.source_type.utm.concat(utm_type) : utm_type; + sd.para.source_type.search = _.isArray(sd.para.source_type.search) ? sd.para.source_type.search.concat(search_type) : search_type; + sd.para.source_type.social = _.isArray(sd.para.source_type.social) ? sd.para.source_type.social.concat(social_type) : social_type; + sd.para.source_type.keyword = _.isObject(sd.para.source_type.keyword) ? _.extend(search_keyword,sd.para.source_type.keyword) : search_keyword; + } + + if(_.isObject(sd.para.heatmap)) { + sd.para.heatmap.clickmap = sd.para.heatmap.clickmap || 'default'; + sd.para.heatmap.scroll_notice_map = sd.para.heatmap.scroll_notice_map || 'default'; + sd.para.heatmap.scroll_delay_time = sd.para.heatmap.scroll_delay_time || 4000; + sd.para.heatmap.scroll_event_duration = sd.para.heatmap.scroll_event_duration || 18000; // The max value of $event_duration property for $WebStay event, in seconds (5 Hours). + sd.para.heatmap.renderRefreshTime = sd.para.heatmap.renderRefreshTime || 1000; + sd.para.heatmap.loadTimeout = sd.para.heatmap.loadTimeout || 1000; + } + // 优化配置 + if(typeof sd.para.server_url === 'object' && sd.para.server_url.length){ + for(i = 0; i < sd.para.server_url.length; i++){ + if (!/sa\.gif[^\/]*$/.test(sd.para.server_url[i])) { + sd.para.server_url[i] = sd.para.server_url[i].replace(/\/sa$/, '/sa.gif').replace(/(\/sa)(\?[^\/]+)$/, '/sa.gif$2'); + } + } + }else if (!/sa\.gif[^\/]*$/.test(sd.para.server_url)) { + sd.para.server_url = sd.para.server_url.replace(/\/sa$/, '/sa.gif').replace(/(\/sa)(\?[^\/]+)$/, '/sa.gif$2'); + } + if(typeof sd.para.server_url === 'string'){ + sd.para.debug_mode_url = sd.para.debug_mode_url || sd.para.server_url.replace('sa.gif', 'debug'); + } + // 是否需要非cache,等于每次请求文件 + if (sd.para.noCache === true) { + sd.para.noCache = '?' + (new Date()).getTime(); + } else { + sd.para.noCache = ''; + } + + if (sd.para.callback_timeout > sd.para.datasend_timeout) { + sd.para.datasend_timeout = sd.para.callback_timeout; + } + if (sd.para.callback_timeout > sd.para.queue_timeout) { + sd.para.queue_timeout = sd.para.callback_timeout; + } + if (sd.para.queue_timeout > sd.para.datasend_timeout) { + sd.para.datasend_timeout = sd.para.queue_timeout; + } + +}; + + +// sa 当前状态管理 +sd.readyState = { + state : 0, + historyState:[], + stateType: { + '1': '1-init未开始', + '2': '2-init开始', + '3': '3-store完成' + }, + getState : function(){ + return this.historyState.join('\n'); + }, + setState:function(n){ + if(String(n) in this.stateType){ + this.state = n; + } + this.historyState.push(this.stateType[n]); + } +}; + + +sd.setPreConfig = function(sa){ + sd.para = sa.para; + sd._q = sa._q; +}; + + +sd.setInitVar= function(){ + sd._t = sd._t || 1 * new Date(); + sd.lib_version = '1.14.23'; + sd.is_first_visitor = false; + // 标准广告系列来源 + sd.source_channel_standard = 'utm_source utm_medium utm_campaign utm_content utm_term'; +}; + +sd.log = function() { + if((_.sessionStorage.isSupport() && sessionStorage.getItem('sensorsdata_jssdk_debug') === 'true') || sd.para.show_log){ + + if(sd.para.show_log === true || sd.para.show_log === 'string' || sd.para.show_log === false){ + arguments[0] = _.formatJsonString(arguments[0]); + } + + if (typeof console === 'object' && console.log) { + try { + return console.log.apply(console, arguments); + } catch (e) { + console.log(arguments[0]); + } + } + } +}; + +/** + * 设置 sessionStorage 开启本地控制台日志输出 + */ +sd.enableLocalLog = function() { + if(_.sessionStorage.isSupport()) { + try { + sessionStorage.setItem('sensorsdata_jssdk_debug', 'true'); + } catch (e) { + sd.log('enableLocalLog error: ' + e.message); + // handle the exception here. + } + } +}; + +/** + * 删除 sessionStorage 关闭本地控制台日志输出 + */ +sd.disableLocalLog = function() { + if(_.sessionStorage.isSupport()) { + sessionStorage.removeItem('sensorsdata_jssdk_debug'); + } +}; + +sd.debug = { + distinct_id: function() { + /* + var relation = { + 'e-0': '未知错误', + 'e-1': 'toState()传值的数据中缺少distinct_id,SDK自动分配distinct_id', + 'e-2': 'toState()传值的数据不是一个有效的JSON字符串,SDK自动分配distinct_id' + }; + var debug_info = relation['e-' + key] || relation['e-0']; + if (sd.para.is_debug === true || sd.para.is_debug.distinct_id === true) { + sd.log(debug_info); + this._sendDebug('distinct_id-' + key + '-' + JSON.stringify(data)); + } + */ + }, + jssdkDebug: function() { + /* + if (sd.para.is_debug === true) { + if(_.isString(recevie_prop)){ + this._sendDebug(recevie_prop); + }else{ + var cookie = store.getCookieName(); + var match = document.cookie.match(new RegExp(cookie + '[^;]+')); + if(match && match[0] ){ + cookie = match[0]; + }else{ + cookie = ''; + } + recevie_prop._jssdk_debug_info = '(' + cookie + ')' + navigator.userAgent; + this._sendDebug(JSON.stringify(recevie_prop)); + } + } + */ + }, + _sendDebug: function(debugString) { + sd.track('_sensorsdata2019_debug', { + _jssdk_debug_info: debugString + }); + }, + apph5: function(obj){ + var name = 'app_h5打通失败-'; + var relation = { + '1': name + 'use_app_track为false', + '2': name + 'Android或者iOS,没有暴露相应方法', + '3.1': name + 'Android校验server_url失败', + '3.2': name + 'iOS校验server_url失败', + '4.1': name + 'H5 校验 iOS server_url 失败', + '4.2': name + 'H5 校验 Android server_url 失败', + '4.3': name + 'H5 数据成功发往 Android', + '4.4': name + 'H5 数据成功发往 iOS' + }; + var output = obj.output; + var step = obj.step; + var data = obj.data || ''; + + // 控制台输出 + if(output === 'all' || output === 'console'){ + sd.log(relation[step]); + } + if((output === 'all' || output === 'code') && _.isObject(sd.para.is_debug) && sd.para.is_debug.apph5){ + if (!data.type || data.type.slice(0, 7) !== 'profile') { + data.properties._jssdk_debug_info = 'apph5-' + String(step); + } + } + } +}; + + var commonWays = { + setOnlineState:function(state){ + if(state === true && _.isObject(sd.para.jsapp) && typeof sd.para.jsapp.getData === 'function'){ + sd.para.jsapp.isOnline = true; + var arr = sd.para.jsapp.getData(); + if(_.isArray(arr) && arr.length > 0){ + _.each(arr,function(str){ + if(_.isJSONString(str)){ + sd.sendState.pushSend(JSON.parse(str)); + } + }); + } + }else{ + sd.para.jsapp.isOnline = false; + } + }, + autoTrackIsUsed:false, + isReady:function(callback){ + callback(); + }, + // 获取谷歌标准参数 + getUtm: function() { + return _.info.campaignParams(); + }, + // 获取当前页面停留时间 + getStayTime: function() { + return ((new Date()) - sd._t) / 1000; + }, + setProfileLocal: function(obj){ + if(!_.localStorage.isSupport()){ + sd.setProfile(obj); + return false; + } + if(!_.isObject(obj) || _.isEmptyObject(obj)){ + return false; + } + var saveData = _.localStorage.parse('sensorsdata_2015_jssdk_profile'); + var isNeedSend = false; + if(_.isObject(saveData) && !_.isEmptyObject(saveData)){ + for(var i in obj){ + if((i in saveData && saveData[i] !== obj[i]) || !(i in saveData)){ + saveData[i] = obj[i]; + isNeedSend = true; + } + } + if(isNeedSend){ + _.localStorage.set('sensorsdata_2015_jssdk_profile',JSON.stringify(saveData)); + sd.setProfile(obj); + } + }else{ + _.localStorage.set('sensorsdata_2015_jssdk_profile',JSON.stringify(obj)); + sd.setProfile(obj); + } + }, + //set init referrer + setInitReferrer: function() { + var _referrer = _.getReferrer(); + sd.setOnceProfile({ + _init_referrer: _referrer, + _init_referrer_host: _.info.pageProp.referrer_host + }); + }, + // set init sessionRegister cookie + setSessionReferrer: function() { + var _referrer = _.getReferrer(); + store.setSessionPropsOnce({ + _session_referrer: _referrer, + _session_referrer_host: _.info.pageProp.referrer_host + }); + }, + // set default referrr and pageurl + setDefaultAttr: function() { + _.info.register({ + _current_url: location.href, + _referrer: _.getReferrer(), + _referring_host: _.info.pageProp.referrer_host + }); + }, + trackHeatMap: function(target, props, callback){ + if((typeof target === 'object') && target.tagName){ + var tagName = target.tagName.toLowerCase(); + var parent_ele = target.parentNode.tagName.toLowerCase(); + if (tagName !== 'button' && tagName !== 'a' && parent_ele !== 'a' && parent_ele !== 'button' && tagName !== 'input' && tagName !== 'textarea' && !_.hasAttribute(target, 'data-sensors-click')) { + heatmap.start(null,target,tagName, props, callback); + } + } + }, + trackAllHeatMap: function(target, props, callback){ + if((typeof target === 'object') && target.tagName){ + var tagName = target.tagName.toLowerCase(); + heatmap.start(null,target,tagName, props, callback); + } + }, + autoTrackSinglePage:function(para,callback){ + if(this.autoTrackIsUsed){ + var url = _.info.pageProp.url; + }else{ + var url = _.info.pageProp.referrer; + } + para = _.isObject(para) ? para : {}; + + para = _.isObject(para) ? para : {}; + + + function getUtm(){ + var utms = _.info.campaignParams(); + var $utms = {}; + for (var i in utms) { + if ((' ' + sd.source_channel_standard + ' ').indexOf(' ' + i + ' ') !== -1) { + $utms['$' + i] = utms[i]; + } else { + $utms[i] = utms[i]; + } + } + return $utms; + } + + if (sd.is_first_visitor && !para.not_set_profile) { + sd.setOnceProfile(_.extend({ + // 暂时隐藏,等extractor都部署上去 $first_landing_page: _.info.pageProp.url.slice(0, sd.para.max_referrer_string_length), + $first_visit_time: new Date(), + $first_referrer: _.getReferrer(), + $first_browser_language: navigator.language || '取值异常', + $first_browser_charset: typeof document.charset === 'string' ? document.charset.toUpperCase() : '取值异常', + $first_traffic_source_type: _.getSourceFromReferrer(), + $first_search_keyword: _.getKeywordFromReferrer() + }, getUtm()) + ); + sd.is_first_visitor = false; + } + if(para.not_set_profile){ + delete para.not_set_profile; + } + + + function closure(p,c){ + sd.track('$pageview', _.extend({ + $referrer: url, + $url: location.href, + $url_path: location.pathname, + $title: document.title + }, p, getUtm()),c + ); + url = location.href; + } + closure(para,callback); + this.autoTrackSinglePage = closure; + }, + autoTrackWithoutProfile: function(para,callback){ + para = _.isObject(para) ? para : {}; + this.autoTrack(_.extend(para,{not_set_profile:true}),callback); + }, + autoTrack: function(para, callback) { + para = _.isObject(para) ? para : {}; + + var utms = _.info.campaignParams(); + var $utms = {}; + for (var i in utms) { + if ((' ' + sd.source_channel_standard + ' ').indexOf(' ' + i + ' ') !== -1) { + $utms['$' + i] = utms[i]; + } else { + $utms[i] = utms[i]; + } + } + // setOnceProfile 如果是新用户,且允许设置profile + if (sd.is_first_visitor && !para.not_set_profile) { + sd.setOnceProfile(_.extend({ + // 暂时隐藏,等extractor都部署上去 $first_landing_page: _.info.pageProp.url.slice(0, sd.para.max_referrer_string_length), + $first_visit_time: new Date(), + $first_referrer: _.getReferrer(), + $first_browser_language: navigator.language || '取值异常', + $first_browser_charset: typeof document.charset === 'string' ? document.charset.toUpperCase() : '取值异常', + $first_traffic_source_type: _.getSourceFromReferrer(), + $first_search_keyword: _.getKeywordFromReferrer() + }, $utms) + ); + sd.is_first_visitor = false; + } + if(para.not_set_profile){ + delete para.not_set_profile; + } + + // 解决单页面的referrer问题 + var current_page_url = location.href; + + if(sd.para.is_single_page){ + _.addHashEvent(function(){ + var referrer = _.getReferrer(current_page_url); + sd.track('$pageview', _.extend({ + $referrer: referrer, + $url: location.href, + $url_path: location.pathname, + $title: document.title + }, $utms, para),callback + ); + current_page_url = location.href; + }); + } + + sd.track('$pageview', _.extend({ + $referrer: _.getReferrer(), + $url: location.href, + $url_path: location.pathname, + $title: document.title + }, $utms, para),callback + ); + this.autoTrackIsUsed=true; + }, + getAnonymousID:function(){ + if(_.isEmptyObject(sd.store._state)){ + return '请先初始化SDK'; + }else{ + // 优先使用临时属性 + return sd.store._state._first_id || sd.store._state.first_id || sd.store._state._distinct_id || sd.store._state.distinct_id; + } + } + + + }; + + // 一些常见的方法 + sd.quick = function() { + var arg = Array.prototype.slice.call(arguments); + var arg0 = arg[0]; + var arg1 = arg.slice(1); + if (typeof arg0 === 'string' && commonWays[arg0]) { + return commonWays[arg0].apply(commonWays, arg1); + } else if (typeof arg0 === 'function') { + arg0.apply(sd, arg1); + } else { + sd.log('quick方法中没有这个功能' + arg[0]); + } + }; + + + /* + * @param {string} event + * @param {string} properties + * */ + sd.track = function(e, p, c) { + if (saEvent.check({event: e, properties: p})) { + saEvent.send({ + type: 'track', + event: e, + properties: p + }, c); + } + }; + + sd.trackLink = function(link,event_name,event_prop){ + if(typeof link === 'object' && link.tagName){ + _.trackLink({ele:link},event_name,event_prop); + }else if(typeof link === 'object' && link.target && link.event){ + _.trackLink(link,event_name,event_prop); + } + }; + // 跟踪链接 + sd.trackLinks = function(link,event_name,event_prop){ + var ele = link; + event_prop = event_prop || {}; + if(!link || (typeof link !== 'object')){ + return false; + } + if (!link.href || /^javascript/.test(link.href) || link.target) { + return false; + } + _.addEvent(link,'click',function(e){ + e.preventDefault(); // 阻止默认跳转 + var hasCalled = false; + setTimeout(track_a_click, 1000); //如果没有回调成功,设置超时回调 + function track_a_click(){ + if (!hasCalled) { + hasCalled = true; + location.href = link.href; //把 A 链接的点击跳转,改成 location 的方式跳转 + } + } + sd.track(event_name, event_prop, track_a_click); //把跳转操作加在callback里 + }); + + }; + + + /* + * @param {object} properties + * */ + sd.setProfile = function(p, c) { + if (saEvent.check({propertiesMust: p})) { + saEvent.send({ + type: 'profile_set', + properties: p + }, c); + } + }; + + sd.setOnceProfile = function(p, c) { + if (saEvent.check({propertiesMust: p})) { + saEvent.send({ + type: 'profile_set_once', + properties: p + }, c); + } + }; + + /* + * @param {object} properties + * */ + sd.appendProfile = function(p, c) { + if (saEvent.check({propertiesMust: p})) { + _.each(p, function(value, key) { + if (_.isString(value)) { + p[key] = [value]; + } else if (_.isArray(value)) { + + } else { + delete p[key]; + sd.log('appendProfile属性的值必须是字符串或者数组'); + } + }); + if (!_.isEmptyObject(p)) { + saEvent.send({ + type: 'profile_append', + properties: p + }, c); + } + } + }; + /* + * @param {object} properties + * */ + sd.incrementProfile = function(p, c) { + var str = p; + if (_.isString(p)) { + p = {} + p[str] = 1; + } + function isChecked(p) { + for (var i in p) { + if (!/-*\d+/.test(String(p[i]))) { + return false; + } + } + return true; + } + + if (saEvent.check({propertiesMust: p})) { + if (isChecked(p)) { + saEvent.send({ + type: 'profile_increment', + properties: p + }, c); + } else { + sd.log('profile_increment的值只能是数字'); + } + } + }; + + sd.deleteProfile = function(c) { + saEvent.send({ + type: 'profile_delete' + }, c); + store.set('distinct_id', _.UUID()); + store.set('first_id',''); + }; + /* + * @param {object} properties + * */ + sd.unsetProfile = function(p, c) { + var str = p; + var temp = {}; + if (_.isString(p)) { + p = []; + p.push(str); + } + if (_.isArray(p)) { + _.each(p, function(v) { + if (_.isString(v)) { + temp[v] = true; + } else { + sd.log('profile_unset给的数组里面的值必须时string,已经过滤掉', v); + } + }); + saEvent.send({ + type: 'profile_unset', + properties: temp + }, c); + } else { + sd.log('profile_unset的参数是数组'); + } + }; + /* + * @param {string} distinct_id + * */ + sd.identify = function(id, isSave) { + if(typeof id === 'number'){ + id = String(id); + } + var firstId = store.getFirstId(); + if (typeof id === 'undefined') { + if(firstId){ + store.set('first_id', _.UUID()); + }else{ + store.set('distinct_id', _.UUID()); + } + } else if (saEvent.check({distinct_id: id})) { + if (isSave === true) { + if(firstId){ + store.set('first_id', id); + }else{ + store.set('distinct_id', id); + } + } else { + if(firstId){ + store.change('first_id', id); + }else{ + store.change('distinct_id', id); + } + } + + } else { + sd.log('identify的参数必须是字符串'); + } + }; + /* + * 这个接口是一个较为复杂的功能,请在使用前先阅读相关说明:http://www.sensorsdata.cn/manual/track_signup.html,并在必要时联系我们的技术支持人员。 + * @param {string} distinct_id + * @param {string} event + * @param {object} properties + * */ + sd.trackSignup = function(id, e, p, c) { + if (saEvent.check({distinct_id: id, event: e, properties: p})) { + var original_id = store.getFirstId() || store.getDistinctId(); + store.set('distinct_id', id); + saEvent.send({ + original_id: original_id, + distinct_id: id, + type: 'track_signup', + event: e, + properties: p + }, c); + } + }; + + /* + * @param {string} testid + * @param {string} groupid + * */ + sd.trackAbtest = function(t, g) { + /* + if (saEvent.check({test_id: t, group_id: g})) { + saEvent.send({ + type: 'track_abtest', + properties: { + test_id: t, + group_id: g + } + }); + }*/ + }; + + /** + * Register a set of properties, which are included with all events. + * + * @param {Object} obj - An object of properties to be registered. + * + */ + sd.registerPage = function(obj) { + if (saEvent.check({properties: obj})) { + _.extend(_.info.currentProps, obj); + } else { + sd.log('register输入的参数有误'); + } + }; + + sd.clearAllRegister = function(arr){ + store.clearAllProps(arr); + }; + + sd.register = function(props) { + if (saEvent.check({properties: props})) { + store.setProps(props); + } else { + sd.log('register输入的参数有误'); + } + }; + + sd.registerOnce = function(props) { + if (saEvent.check({properties: props})) { + store.setPropsOnce(props); + } else { + sd.log('registerOnce输入的参数有误'); + } + }; + + sd.registerSession = function(props) { + if (saEvent.check({properties: props})) { + store.setSessionProps(props); + } else { + sd.log('registerSession输入的参数有误'); + } + }; + + sd.registerSessionOnce = function(props) { + if (saEvent.check({properties: props})) { + store.setSessionPropsOnce(props); + } else { + sd.log('registerSessionOnce输入的参数有误'); + } + }; + + sd.login = function(id, callback){ + if(typeof id === 'number'){ + id = String(id); + } + if (saEvent.check({distinct_id: id})) { + var firstId = store.getFirstId(); + var distinctId = store.getDistinctId(); + if(id !== distinctId){ + if(!firstId){ + store.set('first_id',distinctId); + } + sd.trackSignup(id,'$SignUp', {}, callback); + } else { + callback && callback(); + } + } else { + sd.log('login的参数必须是字符串'); + callback && callback(); + } + }; + + sd.logout = function(isChangeId){ + var firstId = store.getFirstId(); + if(firstId){ + store.set('first_id',''); + if(isChangeId === true){ + store.set('distinct_id',_.UUID()); + }else{ + store.set('distinct_id',firstId); + } + }else{ + sd.log('没有first_id,logout失败'); + } + }; + + sd.getPresetProperties = function(){ + function getUtm(){ + var utms = _.info.campaignParams(); + var $utms = {}; + for (var i in utms) { + if ((' ' + sd.source_channel_standard + ' ').indexOf(' ' + i + ' ') !== -1) { + $utms['$' + i] = utms[i]; + } else { + $utms[i] = utms[i]; + } + } + return $utms; + } + + var obj = { + $referrer: _.info.pageProp.referrer || '', + $referrer_host: _.info.pageProp.referrer ? _.getHostname(_.info.pageProp.referrer) : '', + $url: location.href, + $url_path: location.pathname, + $title: document.title || '', + _distinct_id: store.getDistinctId() + }; + var result = _.extend({}, _.info.properties(),sd.store.getProps(),getUtm(),obj); + if (sd.para.preset_properties.latest_referrer && sd.para.preset_properties.latest_referrer_host) { + result.$latest_referrer_host = result.$latest_referrer === "" ? "" : _.getHostname(result.$latest_referrer); + } + return result; + }; + + +/* +数据处理和发送的流程 +数据批量发送 +*/ + +function BatchSend(){ + //正在发送中的数据,如果后续还有,就不发送 + this.sendingData = 0; +}; + +BatchSend.prototype = { + add : function(data){ + if(_.isObject(data)){ + this.writeStore(data); + if(data.type === 'track_signup' || data.event === '$pageview'){ + this.sendStrategy(); + } + } + }, + remove: function(keys){ + var me = this; + if(this.sendingData > 0){ + --this.sendingData; + } + if(_.isArray(keys) && keys.length > 0){ + _.each(keys,function(key){ + _.localStorage.remove(key); + }); + } + }, + send: function(data){ + var me = this; + var server_url = _.isArray(sd.para.server_url) ? sd.para.server_url[0] : sd.para.server_url; + _.ajax({ + url: server_url, + type: 'POST', + data: 'data_list=' + encodeURIComponent(_.base64Encode(JSON.stringify(data.vals))), + credentials: false, + timeout: sd.para.batch_send.datasend_timeout, + cors: true, + success:function(){ + me.remove(data.keys); + }, + error: function() { + if (me.sendingData > 0) { + --me.sendingData; + } + } + }); + + }, + sendPrepare:function(data){ + var arr = data.vals; + //优化最大发送数据量 + var maxLen = sd.para.batch_send.one_send_max_length; + var arrLen = arr.length; + if(arrLen > 0){ + if(arrLen <= maxLen){ + this.send({ + keys: data.keys, + vals: arr + }); + }else{ + for(var i = 0; i*maxLen < arrLen; i++){ + this.send({ + keys: data.keys.splice(0,maxLen), + vals: arr.splice(0,maxLen) + }); + } + + } + } + }, + sendStrategy:function(){ + //定时发送和次数发送,都存在页面打开没及时发送的问题,所以优化如果是profile和pageview则触发发送 + //次数发送存在不满足次数,永远发送不了的问题,所以选择定时发送 + var data = this.readStore(); + if(data.keys.length > 0 && this.sendingData === 0){ + this.sendingData = Math.ceil(data.vals.length/sd.para.batch_send.one_send_max_length) + this.sendPrepare(data); + } + }, + batchInterval:function(){ + var me = this; + setInterval(function(){ + me.sendStrategy(); + },sd.para.batch_send.send_interval); + }, + readStore:function(){ + var keys = []; + var vals = []; + var obj = {}; + var val = null; + var now = (new Date()).getTime(); + var len = localStorage.length; + for (var i = 0; i < len; i++) { + var key = localStorage.key(i); + if(key.indexOf('sawebjssdk-') === 0 && /^sawebjssdk\-\d+$/.test(key)){ + val = localStorage.getItem(key); + if(val){ + val = _.safeJSONParse(val); + if(val && _.isObject(val)){ + val._flush_time = now; + keys.push(key); + vals.push(val); + }else{ + localStorage.removeItem(key); + sd.log('localStorage-数据parse异常' + val); + } + }else{ + localStorage.removeItem(key); + sd.log('localStorage-数据取值异常' + val); + } + } + } + return { + keys:keys, + vals:vals + }; + }, + writeStore:function(data){ + var uuid = String(Math.random()).slice(2,5)+String(Math.random()).slice(2,5)+String((new Date()).getTime()).slice(3); + localStorage.setItem('sawebjssdk-'+uuid,JSON.stringify(data)); + } +}; + +sd.batchSend = new BatchSend(); + + + + +// 各种发送方式 +var dataSend = {}; + +dataSend.getSendUrl = function(url,data){ + var base64Data = _.base64Encode(data); + var crc = 'crc=' + _.hashCode(base64Data); + if (url.indexOf('?') !== -1) { + return url + '&data=' + encodeURIComponent(base64Data) + '&ext=' + encodeURIComponent(crc); + }else{ + return url + '?data=' + encodeURIComponent(base64Data) + '&ext=' + encodeURIComponent(crc); + } +}; + +dataSend.getSendData = function(data){ + var base64Data = _.base64Encode(data); + var crc = 'crc=' + _.hashCode(base64Data); + return 'data=' + encodeURIComponent(base64Data) + '&ext=' + encodeURIComponent(crc); +}; + + +dataSend.getInstance = function(data){ + var sendType = this.getSendType(data); + var obj = new this[sendType](data); + // 代理模式,重置原方法,统一设置超时 + var start = obj.start; + obj.start = function(){ + if (_.isObject(sd.para.is_debug) && sd.para.is_debug.storage && sd.store.requests) { + sd.store.requests.push({ + name: this.server_url, + initiatorType: this.img ? 'img' : 'xmlhttprequest', // todo: beacon + entryType: "resource", + requestData: this.data + }); + } + var me = this; + start.apply(this, arguments); + setTimeout(function(){ + me.isEnd(true); + },sd.para.callback_timeout); + }; + obj.end = function(){ + this.callback && this.callback(); + var self=this; + setTimeout(function(){ + self.lastClear && self.lastClear(); + },sd.para.datasend_timeout-sd.para.callback_timeout); + }; + obj.isEnd = function(isDelay){ + if(!this.received){ + this.received = true; + this.end(); + var self=this; + if(isDelay){ + if(sd.para.queue_timeout-sd.para.callback_timeout <= 0){ + self.close(); + } else { + setTimeout(function () { + self.close(); + },sd.para.queue_timeout-sd.para.callback_timeout); + } + }else{ + self.close(); + } + } + }; + + return obj; + +}; + +dataSend.getSendType = function(data) { + var supportedSendTypes = ['image', 'ajax', 'beacon']; + var sendType = supportedSendTypes[0]; + + if(data.config && _.indexOf(supportedSendTypes, data.config.send_type) > -1) { + sendType = data.config.send_type; + } else { + sendType = sd.para.send_type; + } + + if (sendType === 'beacon' && typeof navigator.sendBeacon !== "function") { + sendType = 'image'; + } + + if (sendType === 'ajax' && _.isSupportCors() === false) { + sendType = 'image'; + } + + return sendType; +}; + +dataSend.image = function(para){ + this.callback = para.callback; + this.img = document.createElement('img'); + this.img.width = 1; + this.img.height = 1; + // 如果后端没有配置 access-allow-origin 会导致请求错误 + if (sd.para.img_use_crossorigin) { + this.img.crossOrigin = 'anonymous'; + } + this.data = para.data; + this.server_url = dataSend.getSendUrl(para.server_url,para.data); +}; +dataSend.image.prototype.start = function(){ + var me = this; + if (sd.para.ignore_oom) { + this.img.onload = function() { + this.onload = null; + this.onerror = null; + this.onabort = null; + me.isEnd(); + }; + this.img.onerror = function() { + this.onload = null; + this.onerror = null; + this.onabort = null; + me.isEnd(); + }; + this.img.onabort = function() { + this.onload = null; + this.onerror = null; + this.onabort = null; + me.isEnd(); + }; + } + this.img.src = this.server_url; +}; + +dataSend.image.prototype.lastClear=function(){ + this.img.src=""; +} + +dataSend.ajax = function(para){ + this.callback = para.callback; + this.server_url = para.server_url; + this.data = dataSend.getSendData(para.data); +}; +dataSend.ajax.prototype.start = function(){ + var me = this; + _.ajax({ + url: this.server_url, + type: 'POST', + data: this.data, + credentials: false, + timeout:sd.para.datasend_timeout, + cors:true, + success:function(){ + me.isEnd(); + }, + error:function(){ + me.isEnd(); + } + }); +}; + +dataSend.beacon = function(para){ + this.callback = para.callback; + this.server_url = para.server_url; + this.data = dataSend.getSendData(para.data); +}; + +dataSend.beacon.prototype.start = function(){ + var me = this; + if(typeof navigator === 'object' && typeof navigator.sendBeacon === 'function'){ + navigator.sendBeacon(this.server_url,this.data); + } + setTimeout(function(){ + me.isEnd(); + },40); +}; + + + +// 数据发送流程控制 + +var sendState = {}; +sd.sendState = sendState; +// 发送队列 +sendState.queue = _.autoExeQueue(); + +sendState.requestData = null; + +sendState.getSendCall = function(data, config, callback) { + // 点击图渲染模式不发数据 + if(sd.is_heatmap_render_mode){ + return false; + } + + if(sd.readyState.state < 3){ + sd.log('初始化没有完成'); + return false; + } + + data._track_id = Number(String(Math.random()).slice(2, 5) + String(Math.random()).slice(2, 4) + String((new Date()).getTime()).slice(-4)); + if (sd.para.use_client_time) { + data._flush_time = (new Date()).getTime(); + } + + var originData = data; + + data = JSON.stringify(data); + //sd.log(originData); + + this.requestData = { + data: originData, + config: config, + callback: callback + }; + + if(!sd.para.use_app_track_config.use_app_track && sd.para.batch_send && localStorage.length < 200){ + sd.log(originData); + sd.batchSend.add(this.requestData.data); + return false; + } + + // 打通app传数据给app + if(sd.para.use_app_track_config.use_app_track === true || sd.para.use_app_track_config.use_app_track === 'only'){ + //如果有新版,优先用新版 + if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.sensorsdataNativeTracker && _.isObject(window.SensorsData_iOS_JS_Bridge) && window.SensorsData_iOS_JS_Bridge.sensorsdata_app_server_url) { + if(sd.para.use_app_track_config.H5verify){ + sd.debug.apph5({ + data: originData, + step: '4.4', + output:'all' + }); + window.webkit.messageHandlers.sensorsdataNativeTracker.postMessage(JSON.stringify({callType:'app_h5_track', data: _.extend({server_url:sd.para.server_url}, originData)})); + }else{ + sd.debug.apph5({ + data: originData, + step: '4.1', + output:'all' + }); + this.prepareServerUrl(); + } + }else if(_.isObject(window.SensorsData_APP_New_H5_Bridge) && window.SensorsData_APP_New_H5_Bridge.sensorsdata_get_server_url && window.SensorsData_APP_New_H5_Bridge.sensorsdata_track){ + if(sd.para.use_app_track_config.H5verify){ + sd.debug.apph5({ + data: originData, + step: '4.3', + output:'all' + }); + SensorsData_APP_New_H5_Bridge.sensorsdata_track(JSON.stringify(_.extend({server_url:sd.para.server_url},originData))); + }else{ + sd.debug.apph5({ + data: originData, + step: '4.2', + output:'all' + }); + this.prepareServerUrl(); + } + }else if((typeof SensorsData_APP_JS_Bridge === 'object') && (SensorsData_APP_JS_Bridge.sensorsdata_verify || SensorsData_APP_JS_Bridge.sensorsdata_track)){ + // 如果有有校验的版本,优先用校验版 + if(SensorsData_APP_JS_Bridge.sensorsdata_verify){ + // 如果校验通过则结束,不通过则降级改成h5继续发送 + if(!SensorsData_APP_JS_Bridge.sensorsdata_verify(JSON.stringify(_.extend({server_url:sd.para.server_url},originData)))){ + if (sd.para.use_app_track_config.use_app_track_is_send) { + sd.debug.apph5({ + data: originData, + step: '3.1', + output:'all' + }); + this.prepareServerUrl(); + } + }else{ + (typeof callback === 'function') && callback(); + } + }else{ + SensorsData_APP_JS_Bridge.sensorsdata_track(JSON.stringify(_.extend({server_url:sd.para.server_url},originData))); + (typeof callback === 'function') && callback(); + } + }else if((/sensors-verify/.test(navigator.userAgent) || /sa-sdk-ios/.test(navigator.userAgent)) && !window.MSStream){ + var iframe = null; + if(/sensors-verify/.test(navigator.userAgent)){ + var match = navigator.userAgent.match(/sensors-verify\/([^\s]+)/); + if(match && match[0] && (typeof match[1] === 'string') && (match[1].split('?').length === 2)){ + match = match[1].split('?'); + var hostname = null; + var project = null; + try{ + hostname = _.URL(sd.para.server_url).hostname; + project = _.URL(sd.para.server_url).searchParams.get('project') || 'default'; + }catch(e){}; + if (hostname && hostname === match[0] && project && project === match[1]) { + iframe = document.createElement('iframe'); + iframe.setAttribute('src', 'sensorsanalytics://trackEvent?event=' + encodeURIComponent(JSON.stringify(_.extend({server_url:sd.para.server_url},originData)))); + document.documentElement.appendChild(iframe); + iframe.parentNode.removeChild(iframe); + iframe = null; + (typeof callback === 'function') && callback(); + } else { + if (sd.para.use_app_track_config.use_app_track_is_send) { + sd.debug.apph5({ + data: originData, + step: '3.2', + output:'all' + }); + this.prepareServerUrl(); + } + } + } + }else{ + iframe = document.createElement('iframe'); + iframe.setAttribute('src', 'sensorsanalytics://trackEvent?event=' + encodeURIComponent(JSON.stringify(_.extend({server_url:sd.para.server_url},originData)))); + document.documentElement.appendChild(iframe); + iframe.parentNode.removeChild(iframe); + iframe = null; + (typeof callback === 'function') && callback(); + } + }else{ + if(sd.para.use_app_track_config.use_app_track === true && sd.para.use_app_track_config.use_app_track_is_send === true){ + sd.debug.apph5({ + data: originData, + step: '2', + output:'all' + }); + this.prepareServerUrl(); + } + } + }else if(sd.para.use_app_track_config.use_app_track === 'mui'){ + if(_.isObject(window.plus) && window.plus.SDAnalytics && window.plus.SDAnalytics.trackH5Event){ + window.plus.SDAnalytics.trackH5Event(data); + } + } else{ + sd.debug.apph5({ + data: originData, + step: '1', + output:'code' + }); + this.prepareServerUrl(); + } + sd.log(originData); +}; + +sendState.prepareServerUrl = function(){ + if (typeof this.requestData.config === 'object' && this.requestData.config.server_url) { + this.sendCall(this.requestData.config.server_url,this.requestData.callback); + }else if(_.isArray(sd.para.server_url)){ + for(var i =0; i 当前页面的属性 > session的属性 > cookie的属性 > 预定义属性 + + data.properties = _.extend({}, _.info.properties(), store.getProps(), store.getSessionProps(), _.info.currentProps, data.properties); + if(sd.para.preset_properties.latest_referrer && !_.isString(data.properties.$latest_referrer)){ + data.properties.$latest_referrer = '取值异常'; + // TODO + // Do NOT send data here, it will cause too much recursion. + //_.jssdkDebug(data.properties,store.getProps()); + //sd.debug.jssdkDebug(data.properties, store.getProps()); + } + if(sd.para.preset_properties.latest_search_keyword && !_.isString(data.properties.$latest_search_keyword)){ + data.properties.$latest_search_keyword = '取值异常'; + } + if(sd.para.preset_properties.latest_traffic_source_type && !_.isString(data.properties.$latest_traffic_source_type)){ + data.properties.$latest_traffic_source_type = '取值异常'; + } + if(sd.para.preset_properties.latest_landing_page && !_.isString(data.properties.$latest_landing_page)){ + data.properties.$latest_landing_page = '取值异常'; + } + } + + // 如果$time是传入的就用,否则使用服务端时间 + if (data.properties.$time && _.isDate(data.properties.$time)) { + data.time = data.properties.$time * 1; + delete data.properties.$time; + } else { + if (sd.para.use_client_time) { + data.time = (new Date()) * 1; + } + } + // Parse super properties that added by registerPage() + _.parseSuperProperties(data.properties); + + _.filterReservedProperties(data.properties); + _.searchObjDate(data); + _.searchObjString(data); + // 兼容灼洲app端做的$project和$token而加的代码 + _.searchZZAppStyle(data); + + //去掉data里的$option + var data_config = _.searchConfigData(data.properties); + + //判断是否要给数据增加新用户属性 + saNewUser.checkIsAddSign(data); + saNewUser.checkIsFirstTime(data); + + sd.addReferrerHost(data); + sd.addPropsHook(data); + + if (sd.para.debug_mode === true) { + sd.log(data); + this.debugPath(JSON.stringify(data), callback); + } else { + sd.sendState.getSendCall(data,data_config,callback); + } + +}; + + // 发送debug数据请求 +saEvent.debugPath = function(data, callback) { + var _data = data; //存数据 + var url = ''; + if (sd.para.debug_mode_url.indexOf('?') !== -1) { + url = sd.para.debug_mode_url + '&data=' + encodeURIComponent(_.base64Encode(data)); + } else { + url = sd.para.debug_mode_url + '?data=' + encodeURIComponent(_.base64Encode(data)); + } + + _.ajax({ + url: url, + type: 'GET', + cors: true, + header: {'Dry-Run': String(sd.para.debug_mode_upload)}, + success:function(data){ + // debug 模式下 提示框 + _.isEmptyObject(data) === true ? alert('debug数据发送成功' + _data) : alert('debug失败 错误原因' + JSON.stringify(data)); + } + }); + +}; + +/* +cookie的数据存储 +初始化cookie里的distinct_id +*/ + + var store = sd.store = { + requests: [], + _sessionState: {}, + _state: { + distinct_id: '', + first_id: '', + props: {} + }, + getProps: function() { + return this._state.props || {}; + }, + getSessionProps: function() { + return this._sessionState; + }, + getDistinctId: function() { + return this._state._distinct_id || this._state.distinct_id; + }, + getUnionId: function() { + var obj = {}; + var firstId = this._state._first_id || this._state.first_id, distinct_id = this._state._distinct_id || this._state.distinct_id; + if (firstId && distinct_id) { + obj.login_id = distinct_id; + obj.anonymous_id = firstId; + } else { + obj.anonymous_id = distinct_id; + } + return obj; + }, + getFirstId: function(){ + return this._state._first_id || this._state.first_id; + }, + toState: function(ds) { + var state = null; + if (ds != null && _.isJSONString(ds)) { + state = JSON.parse(ds); + this._state = _.extend(state); + if (state.distinct_id) { + if(typeof(state.props) === 'object'){ + for(var key in state.props){ + if(typeof state.props[key] === 'string'){ + state.props[key] = state.props[key].slice(0, sd.para.max_referrer_string_length); + } + } + this.save(); + } + + } else { + this.set('distinct_id', _.UUID()); + sd.debug.distinct_id('1', ds); + } + } else { + this.set('distinct_id', _.UUID()); + sd.debug.distinct_id('2', ds); + } + }, + initSessionState: function() { + var ds = _.cookie.get('sensorsdata2015session'); + var state = null; + if (ds !== null && (typeof (state = JSON.parse(ds)) === 'object')) { + this._sessionState = state || {}; + } + }, + + setOnce: function(a, b) { + if (!(a in this._state)) { + this.set(a, b); + } + }, + set: function(name, value) { + this._state = this._state || {}; + this._state[name] = value; + // 如果set('first_id') 或者 set('distinct_id'),删除对应的临时属性 + if (name === 'first_id') { + delete this._state._first_id; + } else if (name === 'distinct_id') { + delete this._state._distinct_id; + } + this.save(); + }, + // 针对当前页面修改 + change: function(name, value) { + // 为临时属性名增加前缀 _ (下划线) + this._state['_' + name] = value; + }, + setSessionProps: function(newp) { + var props = this._sessionState; + _.extend(props, newp); + this.sessionSave(props); + }, + setSessionPropsOnce: function(newp) { + var props = this._sessionState; + _.coverExtend(props, newp); + this.sessionSave(props); + }, + setProps: function(newp,isCover) { + var props = {}; + if(!isCover){ + props = _.extend((this._state.props || {}), newp); + }else{ + props = newp; + } + for(var key in props){ + if(typeof props[key] === 'string'){ + props[key] = props[key].slice(0, sd.para.max_referrer_string_length); + } + } + this.set('props', props); + }, + setPropsOnce: function(newp) { + var props = this._state.props || {}; + _.coverExtend(props, newp); + this.set('props', props); + }, + clearAllProps: function(arr) { + this._sessionState = {}; + if(_.isArray(arr) && arr.length > 0){ + for(var i=0;i '); + } + arr.unshift(this.selector(el)); + if (el.getAttribute && el.getAttribute('id') && (sd.para.heatmap && sd.para.heatmap.element_selector !== 'not_use_id')) return arr.join(' > '); + return this.getDomSelector(el.parentNode, arr); + }, + na : function() { + var a = document.documentElement.scrollLeft || window.pageXOffset; + return parseInt(isNaN(a) ? 0 : a, 10); + }, + i : function() { + var a = 0; + try { + a = o.documentElement && o.documentElement.scrollTop || m.pageYOffset, + a = isNaN(a) ? 0 : a; + } catch (b) { + a = 0; + } + return parseInt(a, 10); + }, + getBrowserWidth : function() { + var a = window.innerWidth || document.body.clientWidth; + return isNaN(a) ? 0 : parseInt(a, 10); + }, + getBrowserHeight : function() { + var a = window.innerHeight || document.body.clientHeight; + return isNaN(a) ? 0 : parseInt(a, 10); + }, + getScrollWidth : function() { + var a = parseInt(document.body.scrollWidth, 10); + return isNaN(a) ? 0 : a; + }, + W : function(a) { + var b = parseInt(+a.clientX + +this.na(), 10); + var a = parseInt(+a.clientY + +this.i(), 10); + return { + x : isNaN(b) ? 0 : b, + y : isNaN(a) ? 0 : a + } + }, + start : function(ev, target, tagName, customProps, callback) { + var userCustomProps = _.isObject(customProps) ? customProps : {}; + var userCallback = _.isFunction(callback) ? callback : _.isFunction(customProps) ? customProps : undefined; + if(sd.para.heatmap && sd.para.heatmap.collect_element && !sd.para.heatmap.collect_element(target)){ + return false; + } + + var selector = this.getDomSelector(target); + var prop = _.getEleInfo({target:target}); + + prop.$element_selector = selector ? selector : ''; + if(sd.para.heatmap && sd.para.heatmap.custom_property) { + var customP = sd.para.heatmap.custom_property(target); + if(_.isObject(customP)){ + prop = _.extend(prop,customP); + } + } + prop = _.extend(prop, userCustomProps); + if(tagName === 'a' && sd.para.heatmap && sd.para.heatmap.isTrackLink === true){ + _.trackLink({event:ev,target:target},'$WebClick',prop); + }else{ + sd.track('$WebClick', prop, userCallback); + } + + }, + hasElement:function(e){ + var path = e._getPath(); + if(_.isArray(path) && (path.length > 0) ){ + for(var i = 0;i sd.para.heatmap.scroll_delay_time && offsetTop - para.$viewport_position !==0) || isClose){ + para.$url = location.href; + para.$title = document.title; + para.$url_path = location.pathname; + para.event_duration = Math.min(sd.para.heatmap.scroll_event_duration, parseInt(delay_time)/1000); + sd.track('$WebStay',para); + } + this.current_time = current_time; + } + }); + + delayTime.current_time = new Date(); + + + _.addEvent(window,'scroll', function () { + if (!checkPage()) { + return false; + } + delayTime.go(); + }); + + _.addEvent(window,'unload',function(){ + if (!checkPage()) { + return false; + } + delayTime.go('notime'); + }); + + + }, + initHeatmap : function() { + var that = this; + if (!_.isObject(sd.para.heatmap) || sd.para.heatmap.clickmap !== 'default') { + return false; + } + + // 验证url,function成功就行,非function认为都是全部 + if (_.isFunction(sd.para.heatmap.collect_url) && !sd.para.heatmap.collect_url()) { + return false; + } + + if (sd.para.heatmap.collect_elements === 'all') { + sd.para.heatmap.collect_elements = 'all'; + } else { + sd.para.heatmap.collect_elements = 'interact'; + } + + if (sd.para.heatmap.collect_elements === 'all') { + _.addEvent(document, 'click', function(e) { + var ev = e || window.event; + if(!ev){ + return false; + } + var target = ev.target || ev.srcElement; + if(typeof target !== 'object'){ + return false; + } + if(typeof target.tagName !== 'string'){ + return false; + } + var tagName = target.tagName.toLowerCase(); + if(tagName === 'body' || tagName === 'html'){ + return false; + } + if(!target || !target.parentNode || !target.parentNode.children){ + return false; + } + var parent_ele = target.parentNode.tagName.toLowerCase(); + if(parent_ele === 'a' || parent_ele === 'button'){ + that.start(ev, target.parentNode, parent_ele); + }else{ + that.start(ev, target, tagName); + } + }); + + } else { + _.addEvent(document, 'click', function(e) { + var ev = e || window.event; + if(!ev){ + return false; + } + var target = ev.target || ev.srcElement; + if(typeof target !== 'object'){ + return false; + } + if(typeof target.tagName !== 'string'){ + return false; + } + var tagName = target.tagName.toLowerCase(); + if(tagName.toLowerCase() === 'body' || tagName.toLowerCase() === 'html'){ + return false; + } + if(!target || !target.parentNode || !target.parentNode.children){ + return false; + } + + var parent_ele = target.parentNode; + + if(tagName === 'a' || tagName === 'button' || tagName === 'input' || tagName === 'textarea' || _.hasAttribute(target, 'data-sensors-click')){ + that.start(ev, target, tagName); + }else if(parent_ele.tagName.toLowerCase() === 'button' || parent_ele.tagName.toLowerCase() === 'a'){ + that.start(ev, parent_ele, target.parentNode.tagName.toLowerCase()); + }else if(tagName === 'area' && parent_ele.tagName.toLowerCase() === 'map' && _.ry(parent_ele).prev().tagName && _.ry(parent_ele).prev().tagName.toLowerCase() === 'img'){ + that.start(ev, _.ry(parent_ele).prev(), _.ry(parent_ele).prev().tagName.toLowerCase()); + }else{ + var hasA = that.hasElement(e); + if(hasA){ + that.start(ev, hasA, hasA.tagName.toLowerCase()); + } + } + }); + } + + }, + initAppH5status : function(){ + function checkProjectAndHost(appUrl){ + function getHostNameAndProject(url){ + var obj = { + hostname:'', + project:'' + }; + try{ + obj.hostname = _.URL(url).hostname; + obj.project = _.URL(url).searchParams.get('project') || 'default'; + }catch(e){console.log(e)}; + return obj; + } + var appObj = getHostNameAndProject(appUrl); + var H5Obj = getHostNameAndProject(sd.para.server_url); + if(appObj.hostname === H5Obj.hostname && appObj.project === H5Obj.project){ + return true; + }else{ + if(sd.para.use_app_track_config.white_list[0]){ + for(var i=0;i= 2){ + return false; + } + sd.setInitVar(); + sd.readyState.setState(2); + sd.initPara(para); + + function app_js_bridge(){ + var app_info = null; + var todo = null; + function setAppInfo(data){ + app_info = data; + if(_.isJSONString(app_info)){ + app_info = JSON.parse(app_info); + } + if(todo){ + todo(app_info); + todo = null; + app_info = null; + } + } + //android + function getAndroid(){ + if(typeof window.SensorsData_APP_JS_Bridge === 'object' && window.SensorsData_APP_JS_Bridge.sensorsdata_call_app){ + app_info = SensorsData_APP_JS_Bridge.sensorsdata_call_app(); + if(_.isJSONString(app_info)){ + app_info = JSON.parse(app_info); + } + } + } + //ios + window.sensorsdata_app_js_bridge_call_js = function(data){ + setAppInfo(data); + }; + // 通知iOS + function calliOS() { + if (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) { + var iframe = document.createElement("iframe"); + iframe.setAttribute("src", "sensorsanalytics://getAppInfo"); + document.documentElement.appendChild(iframe); + iframe.parentNode.removeChild(iframe); + iframe = null; + } + } + sd.getAppStatus = function(func){ + calliOS(); + //先获取能直接取到的安卓,ios是异步的不需要操作 + getAndroid(); + // 不传参数,直接返回数据 + if(!func){ + return app_info; + app_info = null; + }else{ + //如果传参数,保存参数。如果有数据直接执行,没数据时保存 + if(app_info === null){ + todo = func; + }else{ + func(app_info); + app_info = null; + } + } + }; + } + + heatmap.prepare(function(){ + app_js_bridge(); + // 初始化referrer等页面属性 1.6 + _.info.initPage(); + + if(sd.para.is_track_single_page){ + _.addSinglePageEvent(function (last_url) { + var sendData = function(extraData) { + extraData = extraData || {}; + if (last_url !== location.href) { + _.info.pageProp.referrer = last_url; + sd.quick("autoTrack", _.extend({$url: location.href, $referrer: last_url}, extraData)); + } + }; + if (typeof sd.para.is_track_single_page === "boolean") { + sendData(); + } else if (typeof sd.para.is_track_single_page === "function") { + var returnValue = sd.para.is_track_single_page(); + if (_.isObject(returnValue)) { + sendData(returnValue); + } else if (returnValue === true) { + sendData(); + } + } + }); + } + // 支持localstorage且开启了batch_send + if (sd.para.batch_send) { + sd.batchSend.batchInterval(); + } + // 初始化distinct_id + sd.store.init(); + + sd.readyState.setState(3); + // 发送数据 + if(sd._q && _.isArray(sd._q) && sd._q.length > 0 ){ + _.each(sd._q, function(content) { + sd[content[0]].apply(sd, Array.prototype.slice.call(content[1])); + }); + } + + }); + +}; + +var methods = ['track','quick','register','registerPage','registerOnce','trackSignup', 'setProfile','setOnceProfile','appendProfile', 'incrementProfile', 'deleteProfile', 'unsetProfile', 'identify','login','logout','trackLink','clearAllRegister']; + +_.each(methods, function(method) { + var oldFunc = sd[method]; + sd[method] = function() { + if (!sd.readyState.getState()) { + try { + console.error('请先初始化神策JS SDK'); + } catch (e) {} + return; + } + return oldFunc.apply(sd, arguments); + }; +}); + + + +if (typeof window['sensorsDataAnalytic201505'] === 'string'){ + //异步或者同步 + sd.setPreConfig(window[sensorsDataAnalytic201505]); + window[sensorsDataAnalytic201505] = sd; + sd.init(); + window['sensorsDataAnalytic201505'] = sd; +} else if (typeof window['sensorsDataAnalytic201505'] === 'undefined'){ + //module模式,或者webpack打包 + window['sensorsDataAnalytic201505'] = sd; + return sd; +} else { + //已经使用过以上两种方式的话 + return window['sensorsDataAnalytic201505']; +} + + + + +}catch(err){ + if (typeof console === 'object' && console.log) { + try {console.log(err)} catch (e) {}; + } +} + + + +}); \ No newline at end of file diff --git a/demo/src/main/assets/test.html b/demo/src/main/assets/test.html new file mode 100644 index 0000000..1a5cf75 --- /dev/null +++ b/demo/src/main/assets/test.html @@ -0,0 +1,114 @@ + + + + + + Web SDK demo + + + + + +

测试

+ 锚点 +
+
+ baidu +
+
+
+
+
+
+
+ 点击按钮触发 + + + +
+ 测试的checkbox点击 +
+ +
+
+ +
+
+ +
+
+ +
+
+ + + + + + + + diff --git a/demo/src/main/assets/visual_h5_test/definedemo.html b/demo/src/main/assets/visual_h5_test/definedemo.html new file mode 100755 index 0000000..a38a20d --- /dev/null +++ b/demo/src/main/assets/visual_h5_test/definedemo.html @@ -0,0 +1,148 @@ + + + + + + Document + + + + + +
+
+ overflow +
+
+
+ a1 + a2 +
+
+
+
+
+ 浮层测试 display +
+
+
点击显示浮层
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ + + \ No newline at end of file diff --git a/demo/src/main/assets/visual_h5_test/defineindex.js b/demo/src/main/assets/visual_h5_test/defineindex.js new file mode 100755 index 0000000..464f5e5 --- /dev/null +++ b/demo/src/main/assets/visual_h5_test/defineindex.js @@ -0,0 +1,50 @@ + + (function(para) { + var p = para.sdk_url, n = para.name, w = window, d = document, s = 'script',x = null,y = null; + if(typeof(w['sensorsDataAnalytic201505']) !== 'undefined') { + return false; + } + w['sensorsDataAnalytic201505'] = n;//'sensors' + w[n] = w[n] || function(a) {return function() {(w[n]._q = w[n]._q || []).push([a, arguments]);}}; + var ifs = ['track','quick','register','registerPage','registerOnce','trackSignup', 'trackAbtest', 'setProfile','setOnceProfile','appendProfile', 'incrementProfile', 'deleteProfile', 'unsetProfile', 'identify','login','logout','trackLink','clearAllRegister','getAppStatus']; + for (var i = 0; i < ifs.length; i++) { + w[n][ifs[i]] = w[n].call(null, ifs[i]); + } + if (!w[n]._t) { + x = d.createElement(s), y = d.getElementsByTagName(s)[0]; + x.async = 1; + x.src = p; + x.setAttribute('charset','UTF-8'); + w[n].para = para; + y.parentNode.insertBefore(x, y); + } + })({ + sdk_url:'./sensorsdata.full.js', + name: 'sensors', + //数据接收地址 + server_url:'https://sdkdebugtest.datasink.sensorsdata.cn/sa?project=default&token=cfb8b60e42e0ae9b', + //是否开启全埋点,配置 heatmap:{} 为开启,不配置 heatmap 为关闭全埋点 + heatmap:{}, + is_track_single_page:true, + //打通参数设置,server_url 白名单校验 server_url + app_js_bridge:{ + white_list:[ + 'https://newsdktest.datasink.sensorsdata.cn/sa?project=chuqiangsheng&token=5a394d2405c147ca', + 'http://10.120.51.215:8106/sa?project=default&token=schemaLimited-0AUNwDG0' + ], + } + }); + + sensors.quick('autoTrack'); + + + // window.SensorsData_APP_JS_Bridge = { + // sensorsdata_define_mode : function(data){ + + // }, + // sensorsdata_track:function(data){ + // console.log(data); + // } + // }; + + \ No newline at end of file diff --git a/demo/src/main/assets/visual_h5_test/sensorsdata.full.js b/demo/src/main/assets/visual_h5_test/sensorsdata.full.js new file mode 100755 index 0000000..9eb044c --- /dev/null +++ b/demo/src/main/assets/visual_h5_test/sensorsdata.full.js @@ -0,0 +1,4601 @@ +; +(function(factory) { + if (typeof exports === 'object' && typeof module === 'object') { + module.exports = factory(); + } else { + factory(); + } +})(function() { + + try { + + + + var sd = {}; + + var _ = sd._ = {}; + + if (typeof JSON !== 'object') { + JSON = {} + }(function() { + 'use strict'; + var rx_one = /^[\],:{}\s]*$/, + rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, + rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, + rx_four = /(?:^|:|,)(?:\s*\[)+/g, + rx_escapable = /[\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; + + function f(n) { + return n < 10 ? '0' + n : n + } + + function this_value() { + return this.valueOf() + } + if (typeof Date.prototype.toJSON !== 'function') { + Date.prototype.toJSON = function() { + return isFinite(this.valueOf()) ? this.getUTCFullYear() + '-' + f(this.getUTCMonth() + 1) + '-' + f(this.getUTCDate()) + 'T' + f(this.getUTCHours()) + ':' + f(this.getUTCMinutes()) + ':' + f(this.getUTCSeconds()) + 'Z' : null + }; + Boolean.prototype.toJSON = this_value; + Number.prototype.toJSON = this_value; + String.prototype.toJSON = this_value + } + var gap, indent, meta, rep; + + function quote(string) { + rx_escapable.lastIndex = 0; + return rx_escapable.test(string) ? '"' + string.replace(rx_escapable, function(a) { + var c = meta[a]; + return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4) + }) + '"' : '"' + string + '"' + } + + function str(key, holder) { + var i, k, v, length, mind = gap, + partial, value = holder[key]; + if (value && typeof value === 'object' && typeof value.toJSON === 'function') { + value = value.toJSON(key) + } + if (typeof rep === 'function') { + value = rep.call(holder, key, value) + } + switch (typeof value) { + case 'string': + return quote(value); + case 'number': + return isFinite(value) ? String(value) : 'null'; + case 'boolean': + case 'null': + return String(value); + case 'object': + if (!value) { + return 'null' + } + gap += indent; + partial = []; + if (Object.prototype.toString.apply(value) === '[object Array]') { + length = value.length; + for (i = 0; i < length; i += 1) { + partial[i] = str(i, value) || 'null' + } + v = partial.length === 0 ? '[]' : gap ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : '[' + partial.join(',') + ']'; + gap = mind; + return v + } + if (rep && typeof rep === 'object') { + length = rep.length; + for (i = 0; i < length; i += 1) { + if (typeof rep[i] === 'string') { + k = rep[i]; + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v) + } + } + } + } else { + for (k in value) { + if (Object.prototype.hasOwnProperty.call(value, k)) { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v) + } + } + } + } + v = partial.length === 0 ? '{}' : gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : '{' + partial.join(',') + '}'; + gap = mind; + return v + } + } + if (typeof JSON.stringify !== 'function') { + meta = { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"': '\\"', + '\\': '\\\\' + }; + JSON.stringify = function(value, replacer, space) { + var i; + gap = ''; + indent = ''; + if (typeof space === 'number') { + for (i = 0; i < space; i += 1) { + indent += ' ' + } + } else if (typeof space === 'string') { + indent = space + } + rep = replacer; + if (replacer && typeof replacer !== 'function' && (typeof replacer !== 'object' || typeof replacer.length !== 'number')) { + throw new Error('JSON.stringify') + } + return str('', { + '': value + }) + } + } + if (typeof JSON.parse !== 'function') { + JSON.parse = function(text, reviver) { + var j; + + function walk(holder, key) { + var k, v, value = holder[key]; + if (value && typeof value === 'object') { + for (k in value) { + if (Object.prototype.hasOwnProperty.call(value, k)) { + v = walk(value, k); + if (v !== undefined) { + value[k] = v + } else { + delete value[k] + } + } + } + } + return reviver.call(holder, key, value) + } + text = String(text); + rx_dangerous.lastIndex = 0; + if (rx_dangerous.test(text)) { + text = text.replace(rx_dangerous, function(a) { + return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4) + }) + } + if (rx_one.test(text.replace(rx_two, '@').replace(rx_three, ']').replace(rx_four, ''))) { + j = eval('(' + text + ')'); + return typeof reviver === 'function' ? walk({ + '': j + }, '') : j + } + throw new SyntaxError('JSON.parse') + } + } + }()); + + + + (function() { + + var ArrayProto = Array.prototype; + var FuncProto = Function.prototype; + var ObjProto = Object.prototype; + var slice = ArrayProto.slice; + var toString = ObjProto.toString; + var hasOwnProperty = ObjProto.hasOwnProperty; + var nativeBind = FuncProto.bind; + var nativeForEach = ArrayProto.forEach; + var nativeIndexOf = ArrayProto.indexOf; + var nativeIsArray = Array.isArray; + var breaker = {}; + + var each = _.each = function(obj, iterator, context) { + if (obj == null) { + return false; + } + if (nativeForEach && obj.forEach === nativeForEach) { + obj.forEach(iterator, context); + } else if (obj.length === +obj.length) { + for (var i = 0, l = obj.length; i < l; i++) { + if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) { + return false; + } + } + } else { + for (var key in obj) { + if (hasOwnProperty.call(obj, key)) { + if (iterator.call(context, obj[key], key, obj) === breaker) { + return false; + } + } + } + } + }; + + _.extend = function(obj) { + each(slice.call(arguments, 1), function(source) { + for (var prop in source) { + if (source[prop] !== void 0) { + obj[prop] = source[prop]; + } + } + }); + return obj; + }; + _.extend2Lev = function(obj) { + each(slice.call(arguments, 1), function(source) { + for (var prop in source) { + if (source[prop] !== void 0) { + if (_.isObject(source[prop]) && _.isObject(obj[prop])) { + _.extend(obj[prop], source[prop]); + } else { + obj[prop] = source[prop]; + } + } + } + }); + return obj; + }; + _.coverExtend = function(obj) { + each(slice.call(arguments, 1), function(source) { + for (var prop in source) { + if (source[prop] !== void 0 && obj[prop] === void 0) { + obj[prop] = source[prop]; + } + } + }); + return obj; + }; + + _.isArray = nativeIsArray || function(obj) { + return toString.call(obj) === '[object Array]'; + }; + + _.isFunction = function(f) { + if (!f) { + return false; + } + try { + return /^\s*\bfunction\b/.test(f); + } catch (x) { + return false; + } + }; + + _.isArguments = function(obj) { + return !!(obj && hasOwnProperty.call(obj, 'callee')); + }; + + _.toArray = function(iterable) { + if (!iterable) { + return []; + } + if (iterable.toArray) { + return iterable.toArray(); + } + if (_.isArray(iterable)) { + return slice.call(iterable); + } + if (_.isArguments(iterable)) { + return slice.call(iterable); + } + return _.values(iterable); + }; + + _.values = function(obj) { + var results = []; + if (obj == null) { + return results; + } + each(obj, function(value) { + results[results.length] = value; + }); + return results; + }; + + + _.indexOf = function(arr, target) { + var indexof = arr.indexOf; + if (indexof) { + return indexof.call(arr, target); + } else { + for (var i = 0; i < arr.length; i++) { + if (target === arr[i]) { + return i; + } + } + return -1; + } + }; + + _.hasAttribute = function(ele, attr) { + if (ele.hasAttribute) { + return ele.hasAttribute(attr); + } else { + return !!(ele.attributes[attr] && ele.attributes[attr].specified); + } + }; + + _.filter = function(arr, fn, self) { + var hasOwn = Object.prototype.hasOwnProperty; + if (arr.filter) { + return arr.filter(fn); + } + var ret = []; + for (var i = 0; i < arr.length; i++) { + if (!hasOwn.call(arr, i)) { + continue; + } + var val = arr[i]; + if (fn.call(self, val, i, arr)) { + ret.push(val); + } + } + return ret; + }; + + _.inherit = function(subclass, superclass) { + subclass.prototype = new superclass(); + subclass.prototype.constructor = subclass; + subclass.superclass = superclass.prototype; + return subclass; + }; + + _.trim = function(str) { + return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); + }; + + _.isObject = function(obj) { + if (obj == null) { + return false; + } else { + return (toString.call(obj) == '[object Object]'); + } + }; + + _.isEmptyObject = function(obj) { + if (_.isObject(obj)) { + for (var key in obj) { + if (hasOwnProperty.call(obj, key)) { + return false; + } + } + return true; + } + return false; + }; + + _.isUndefined = function(obj) { + return obj === void 0; + }; + + _.isString = function(obj) { + return toString.call(obj) == '[object String]'; + }; + + _.isDate = function(obj) { + return toString.call(obj) == '[object Date]'; + }; + + _.isBoolean = function(obj) { + return toString.call(obj) == '[object Boolean]'; + }; + + _.isNumber = function(obj) { + return (toString.call(obj) == '[object Number]' && /[\d\.]+/.test(String(obj))); + }; + + _.isElement = function(obj) { + return !!(obj && obj.nodeType === 1); + }; + + _.isJSONString = function(str) { + try { + JSON.parse(str); + } catch (e) { + return false; + } + return true; + }; + _.safeJSONParse = function(str) { + var val = null; + try { + val = JSON.parse(str); + } catch (e) { + return false; + } + return val; + }; + _.decodeURIComponent = function(val) { + var result = val; + try { + result = decodeURIComponent(val); + } catch (e) { + result = val; + } + return result; + }; + + _.encodeDates = function(obj) { + _.each(obj, function(v, k) { + if (_.isDate(v)) { + obj[k] = _.formatDate(v); + } else if (_.isObject(v)) { + obj[k] = _.encodeDates(v); + } + }); + return obj; + }; + + _.mediaQueriesSupported = function() { + return (typeof window.matchMedia != "undefined" || typeof window.msMatchMedia != "undefined"); + }; + + _.getScreenOrientation = function() { + var screenOrientationAPI = screen.msOrientation || screen.mozOrientation || (screen.orientation || {}).type; + var screenOrientation = '未取到值'; + if (screenOrientationAPI) { + screenOrientation = screenOrientationAPI.indexOf('landscape') > -1 ? 'landscape' : 'portrait'; + } else if (_.mediaQueriesSupported()) { + var matchMediaFunc = window.matchMedia || window.msMatchMedia; + if (matchMediaFunc("(orientation: landscape)").matches) { + screenOrientation = 'landscape'; + } else if (matchMediaFunc("(orientation: portrait)").matches) { + screenOrientation = 'portrait'; + } + } + return screenOrientation; + }; + + _.now = Date.now || function() { + return new Date().getTime(); + }; + + _.throttle = function(func, wait, options) { + var context, args, result; + var timeout = null; + var previous = 0; + if (!options) options = {}; + var later = function() { + previous = options.leading === false ? 0 : _.now(); + timeout = null; + result = func.apply(context, args); + if (!timeout) context = args = null; + }; + return function() { + var now = _.now(); + if (!previous && options.leading === false) previous = now; + var remaining = wait - (now - previous); + context = this; + args = arguments; + if (remaining <= 0 || remaining > wait) { + if (timeout) { + clearTimeout(timeout); + timeout = null; + } + previous = now; + result = func.apply(context, args); + if (!timeout) context = args = null; + } else if (!timeout && options.trailing !== false) { + timeout = setTimeout(later, remaining); + } + return result; + }; + }; + + _.hashCode = function(str) { + if (typeof str !== 'string') { + return 0; + } + var hash = 0; + var char = null; + if (str.length == 0) { + return hash; + } + for (var i = 0; i < str.length; i++) { + char = str.charCodeAt(i); + hash = ((hash << 5) - hash) + char; + hash = hash & hash; + } + return hash; + }; + + _.formatDate = function(d) { + function pad(n) { + return n < 10 ? '0' + n : n; + } + + return d.getFullYear() + '-' + + pad(d.getMonth() + 1) + '-' + + pad(d.getDate()) + ' ' + + pad(d.getHours()) + ':' + + pad(d.getMinutes()) + ':' + + pad(d.getSeconds()) + '.' + + pad(d.getMilliseconds()); + }; + + _.searchObjDate = function(o) { + if (_.isObject(o)) { + _.each(o, function(a, b) { + if (_.isObject(a)) { + _.searchObjDate(o[b]); + } else { + if (_.isDate(a)) { + o[b] = _.formatDate(a); + } + } + }); + } + }; + + _.searchZZAppStyle = function(data) { + if (typeof data.properties.$project !== 'undefined') { + data.project = data.properties.$project; + delete data.properties.$project; + } + if (typeof data.properties.$token !== 'undefined') { + data.token = data.properties.$token; + delete data.properties.$token; + } + }; + + _.formatJsonString = function(obj) { + try { + return JSON.stringify(obj, null, ' '); + } catch (e) { + return JSON.stringify(obj); + } + }; + + _.formatString = function(str) { + if (str.length > sd.para.max_string_length) { + sd.log('字符串长度超过限制,已经做截取--' + str); + return str.slice(0, sd.para.max_string_length); + } else { + return str; + } + }; + + _.searchObjString = function(o) { + if (_.isObject(o)) { + _.each(o, function(a, b) { + if (_.isObject(a)) { + _.searchObjString(o[b]); + } else { + if (_.isString(a)) { + o[b] = _.formatString(a); + } + } + }); + } + }; + + _.parseSuperProperties = function(obj) { + if (_.isObject(obj)) { + _.each(obj, function(value, key) { + if (_.isFunction(value)) { + try { + obj[key] = value(); + if (_.isFunction(obj[key])) { + sd.log("您的属性- " + key + ' 格式不满足要求,我们已经将其删除'); + delete obj[key]; + } + } catch (e) { + delete obj[key]; + sd.log("您的属性- " + key + ' 抛出了异常,我们已经将其删除'); + } + } + }); + _.strip_sa_properties(obj); + } + }; + + + _.filterReservedProperties = function(obj) { + var reservedFields = ['distinct_id', 'user_id', 'id', 'date', 'datetime', 'event', 'events', 'first_id', 'original_id', 'device_id', 'properties', 'second_id', 'time', 'users']; + if (!_.isObject(obj)) { + return; + } + _.each(reservedFields, function(key, index) { + if (!(key in obj)) { + return; + } + if (index < 3) { + delete obj[key]; + sd.log("您的属性- " + key + '是保留字段,我们已经将其删除') + } else { + sd.log("您的属性- " + key + '是保留字段,请避免其作为属性名') + } + }); + } + + _.searchConfigData = function(data) { + if (typeof data === 'object' && data.$option) { + var data_config = data.$option; + delete data.$option; + return data_config; + } else { + return {}; + } + } + + + _.unique = function(ar) { + var temp, n = [], + o = {}; + for (var i = 0; i < ar.length; i++) { + temp = ar[i]; + if (!(temp in o)) { + o[temp] = true; + n.push(temp); + } + } + return n; + }; + + _.strip_sa_properties = function(p) { + if (!_.isObject(p)) { + return p; + } + _.each(p, function(v, k) { + if (_.isArray(v)) { + var temp = []; + _.each(v, function(arrv) { + if (_.isString(arrv)) { + temp.push(arrv); + } else { + sd.log('您的数据-', k, v, '的数组里的值必须是字符串,已经将其删除'); + } + }); + if (temp.length !== 0) { + p[k] = temp; + } else { + delete p[k]; + sd.log('已经删除空的数组'); + } + } + if (!(_.isString(v) || _.isNumber(v) || _.isDate(v) || _.isBoolean(v) || _.isArray(v) || _.isFunction(v) || (k === '$option'))) { + sd.log('您的数据-', k, v, '-格式不满足要求,我们已经将其删除'); + delete p[k]; + } + }); + return p; + }; + + _.strip_empty_properties = function(p) { + var ret = {}; + _.each(p, function(v, k) { + if (v != null) { + ret[k] = v; + } + }); + return ret; + }; + + _.utf8Encode = function(string) { + string = (string + '').replace(/\r\n/g, '\n').replace(/\r/g, '\n'); + + var utftext = '', + start, end; + var stringl = 0, + n; + + start = end = 0; + stringl = string.length; + + for (n = 0; n < stringl; n++) { + var c1 = string.charCodeAt(n); + var enc = null; + + if (c1 < 128) { + end++; + } else if ((c1 > 127) && (c1 < 2048)) { + enc = String.fromCharCode((c1 >> 6) | 192, (c1 & 63) | 128); + } else { + enc = String.fromCharCode((c1 >> 12) | 224, ((c1 >> 6) & 63) | 128, (c1 & 63) | 128); + } + if (enc !== null) { + if (end > start) { + utftext += string.substring(start, end); + } + utftext += enc; + start = end = n + 1; + } + } + + if (end > start) { + utftext += string.substring(start, string.length); + } + + return utftext; + }; + + _.base64Encode = function(data) { + if (typeof btoa === 'function') { + return btoa(encodeURIComponent(data).replace(/%([0-9A-F]{2})/g, function(match, p1) { + return String.fromCharCode('0x' + p1); + })); + } + data = String(data); + var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, + ac = 0, + enc = '', + tmp_arr = []; + if (!data) { + return data; + } + data = _.utf8Encode(data); + do { + o1 = data.charCodeAt(i++); + o2 = data.charCodeAt(i++); + o3 = data.charCodeAt(i++); + + bits = o1 << 16 | o2 << 8 | o3; + + h1 = bits >> 18 & 0x3f; + h2 = bits >> 12 & 0x3f; + h3 = bits >> 6 & 0x3f; + h4 = bits & 0x3f; + tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4); + } while (i < data.length); + + enc = tmp_arr.join(''); + + switch (data.length % 3) { + case 1: + enc = enc.slice(0, -2) + '=='; + break; + case 2: + enc = enc.slice(0, -1) + '='; + break; + } + + return enc; + }; + + + _.UUID = (function() { + var T = function() { + var d = 1 * new Date(), + i = 0; + while (d == 1 * new Date()) { + i++; + } + return d.toString(16) + i.toString(16); + }; + var R = function() { + return Math.random().toString(16).replace('.', ''); + }; + var UA = function(n) { + var ua = navigator.userAgent, + i, ch, buffer = [], + ret = 0; + + function xor(result, byte_array) { + var j, tmp = 0; + for (j = 0; j < byte_array.length; j++) { + tmp |= (buffer[j] << j * 8); + } + return result ^ tmp; + } + + for (i = 0; i < ua.length; i++) { + ch = ua.charCodeAt(i); + buffer.unshift(ch & 0xFF); + if (buffer.length >= 4) { + ret = xor(ret, buffer); + buffer = []; + } + } + + if (buffer.length > 0) { + ret = xor(ret, buffer); + } + + return ret.toString(16); + }; + + return function() { + var se = String(screen.height * screen.width); + if (se && /\d{5,}/.test(se)) { + se = se.toString(16); + } else { + se = String(Math.random() * 31242).replace('.', '').slice(0, 8); + } + var val = (T() + '-' + R() + '-' + UA() + '-' + se + '-' + T()); + if (val) { + return val; + } else { + return (String(Math.random()) + String(Math.random()) + String(Math.random())).slice(2, 15); + } + + }; + })(); + + + _.getQueryParam = function(url, param) { + param = param.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]"); + url = _.decodeURIComponent(url); + var regexS = "[\\?&]" + param + "=([^&#]*)", + regex = new RegExp(regexS), + results = regex.exec(url); + if (results === null || (results && typeof(results[1]) !== 'string' && results[1].length)) { + return ''; + } else { + return _.decodeURIComponent(results[1]); + } + }; + + _.urlParse = function(para) { + var URLParser = function(a) { + this._fields = { + Username: 4, + Password: 5, + Port: 7, + Protocol: 2, + Host: 6, + Path: 8, + URL: 0, + QueryString: 9, + Fragment: 10 + }; + this._values = {}; + this._regex = null; + this._regex = /^((\w+):\/\/)?((\w+):?(\w+)?@)?([^\/\?:]+):?(\d+)?(\/?[^\?#]+)?\??([^#]+)?#?(\w*)/; + + if (typeof a != 'undefined') { + this._parse(a) + } + }; + URLParser.prototype.setUrl = function(a) { + this._parse(a) + }; + URLParser.prototype._initValues = function() { + for (var a in this._fields) { + this._values[a] = '' + } + }; + URLParser.prototype.addQueryString = function(queryObj) { + if (typeof queryObj !== 'object') { + return false; + } + var query = this._values.QueryString || ''; + for (var i in queryObj) { + if (new RegExp(i + '[^&]+').test(query)) { + query = query.replace(new RegExp(i + '[^&]+'), i + '=' + queryObj[i]); + } else { + if (query.slice(-1) === '&') { + query = query + i + '=' + queryObj[i]; + } else { + if (query === '') { + query = i + '=' + queryObj[i]; + } else { + query = query + '&' + i + '=' + queryObj[i]; + } + } + } + } + this._values.QueryString = query; + }; + URLParser.prototype.getUrl = function() { + var url = ''; + url += this._values.Origin; + url += this._values.Port ? ':' + this._values.Port : ''; + url += this._values.Path; + url += this._values.QueryString ? '?' + this._values.QueryString : ''; + url += this._values.Fragment ? '#' + this._values.Fragment : ''; + return url; + }; + + URLParser.prototype.getUrl = function() { + var url = ''; + url += this._values.Origin; + url += this._values.Port ? ':' + this._values.Port : ''; + url += this._values.Path; + url += this._values.QueryString ? '?' + this._values.QueryString : ''; + return url; + }; + URLParser.prototype._parse = function(a) { + this._initValues(); + var b = this._regex.exec(a); + if (!b) { + throw 'DPURLParser::_parse -> Invalid URL' + } + for (var c in this._fields) { + if (typeof b[this._fields[c]] != 'undefined') { + this._values[c] = b[this._fields[c]] + } + } + this._values['Hostname'] = this._values['Host'].replace(/:\d+$/, ''); + this._values['Origin'] = this._values['Protocol'] + '://' + this._values['Hostname']; + + }; + return new URLParser(para); + }; + + + + + + + _.addEvent = function() { + + function fixEvent(event) { + if (event) { + event.preventDefault = fixEvent.preventDefault; + event.stopPropagation = fixEvent.stopPropagation; + event._getPath = fixEvent._getPath; + } + return event; + } + fixEvent._getPath = function() { + var ev = this; + var polyfill = function() { + try { + var element = ev.target; + var pathArr = [element]; + if (element === null || element.parentElement === null) { + return []; + } + while (element.parentElement !== null) { + element = element.parentElement; + pathArr.unshift(element); + } + return pathArr; + } catch (err) { + return []; + } + + }; + return this.path || (this.composedPath && this.composedPath()) || polyfill(); + }; + fixEvent.preventDefault = function() { + this.returnValue = false; + }; + fixEvent.stopPropagation = function() { + this.cancelBubble = true; + }; + + + var register_event = function(element, type, handler) { + var useCapture = _.isObject(sd.para.heatmap) && sd.para.heatmap.useCapture ? true : false; + if (element && element.addEventListener) { + element.addEventListener(type, function(e) { + e._getPath = fixEvent._getPath; + handler.call(this, e); + }, useCapture); + } else { + var ontype = 'on' + type; + var old_handler = element[ontype]; + element[ontype] = makeHandler(element, handler, old_handler); + } + }; + + function makeHandler(element, new_handler, old_handlers) { + var handler = function(event) { + event = event || fixEvent(window.event); + if (!event) { + return undefined; + } + event.target = event.srcElement; + + var ret = true; + var old_result, new_result; + if (typeof old_handlers === 'function') { + old_result = old_handlers(event); + } + new_result = new_handler.call(element, event); + if ((false === old_result) || (false === new_result)) { + ret = false; + } + return ret; + }; + return handler; + } + + register_event.apply(null, arguments); + }; + + + _.addHashEvent = function(callback) { + var hashEvent = ('pushState' in window.history ? 'popstate' : 'hashchange'); + _.addEvent(window, hashEvent, callback); + }; + + _.addSinglePageEvent = function(callback) { + var current_url = location.href; + var historyPushState = window.history.pushState; + var historyReplaceState = window.history.replaceState; + + window.history.pushState = function() { + historyPushState.apply(window.history, arguments); + callback(current_url); + current_url = location.href; + }; + window.history.replaceState = function() { + historyReplaceState.apply(window.history, arguments); + callback(current_url); + current_url = location.href; + }; + + var singlePageEvent = historyPushState ? 'popstate' : 'hashchange'; + _.addEvent(window, singlePageEvent, function() { + callback(current_url); + current_url = location.href; + }); + }; + + _.cookie = { + get: function(name) { + var nameEQ = name + '='; + var ca = document.cookie.split(';'); + for (var i = 0; i < ca.length; i++) { + var c = ca[i]; + while (c.charAt(0) == ' ') { + c = c.substring(1, c.length); + } + if (c.indexOf(nameEQ) == 0) { + return _.decodeURIComponent(c.substring(nameEQ.length, c.length)); + } + } + return null; + }, + set: function(name, value, days, cross_subdomain, is_secure) { + cross_subdomain = typeof cross_subdomain === 'undefined' ? sd.para.cross_subdomain : cross_subdomain; + var cdomain = '', + expires = '', + secure = ''; + days = days == null ? 73000 : days; + + if (cross_subdomain) { + var domain = _.getCurrentDomain(location.href); + if (domain === 'url解析失败') { + domain = ''; + } + cdomain = ((domain) ? '; domain=' + domain : ''); + } + + if (days !== 0) { + var date = new Date(); + if (String(days).slice(-1) === 's') { + date.setTime(date.getTime() + (Number(String(days).slice(0, -1)) * 1000)); + } else { + date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); + } + + expires = '; expires=' + date.toGMTString(); + } + + if (is_secure) { + secure = '; secure'; + } + + document.cookie = name + '=' + encodeURIComponent(value) + expires + + '; path=/' + cdomain + secure; + }, + + remove: function(name, cross_subdomain) { + cross_subdomain = typeof cross_subdomain === 'undefined' ? sd.para.cross_subdomain : cross_subdomain; + _.cookie.set(name, '', -1, cross_subdomain); + + }, + + getCookieName: function(name_prefix, url) { + var sub = ''; + url = url || location.href; + if (sd.para.cross_subdomain === false) { + try { + sub = _.URL(url).hostname; + } catch (e) { + sd.log(e); + + } + if (typeof sub === 'string' && sub !== '') { + sub = 'sajssdk_2015_' + name_prefix + '_' + sub.replace(/\./g, '_'); + } else { + sub = 'sajssdk_2015_root_' + name_prefix; + } + } else { + sub = 'sajssdk_2015_cross_' + name_prefix; + } + return sub; + }, + getNewUser: function() { + var prefix = 'new_user'; + if (this.get('sensorsdata_is_new_user') !== null || this.get(this.getCookieName(prefix)) !== null) { + return true; + } else { + return false; + } + } + }; + _.getElementContent = function(target, tagName) { + var textContent = ''; + var element_content = ''; + if (target.textContent) { + textContent = _.trim(target.textContent); + } else if (target.innerText) { + textContent = _.trim(target.innerText); + } + if (textContent) { + textContent = textContent.replace(/[\r\n]/g, ' ').replace(/[ ]+/g, ' ').substring(0, 255); + } + element_content = textContent || ''; + + if (tagName === 'input' || tagName === 'INPUT') { + if (target.type === 'button' || target.type === 'submit') { + element_content = target.value || ''; + } else if (sd.para.heatmap && (typeof sd.para.heatmap.collect_input === 'function') && sd.para.heatmap.collect_input(target)) { + element_content = target.value || ''; + } + } + return element_content; + }; + _.getEleInfo = function(obj) { + if (!obj.target) { + return false; + } + + var target = obj.target; + var tagName = target.tagName.toLowerCase(); + + + var props = {}; + + props.$element_type = tagName; + props.$element_name = target.getAttribute('name'); + props.$element_id = target.getAttribute('id'); + props.$element_class_name = typeof target.className === 'string' ? target.className : null; + props.$element_target_url = target.getAttribute('href'); + props.$element_content = _.getElementContent(target, tagName); + + + props = _.strip_empty_properties(props); + + props.$url = location.href; + props.$url_path = location.pathname; + props.$title = document.title; + props.$viewport_width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth || 0; + + return props; + + }; + + _.localStorage = { + get: function(name) { + return window.localStorage.getItem(name); + }, + + parse: function(name) { + var storedValue; + try { + storedValue = JSON.parse(_.localStorage.get(name)) || null; + } catch (err) { + sd.log(err); + + } + return storedValue; + }, + + set: function(name, value) { + window.localStorage.setItem(name, value); + }, + + remove: function(name) { + window.localStorage.removeItem(name); + }, + + isSupport: function() { + var supported = true; + try { + var key = '__sensorsdatasupport__'; + var val = 'testIsSupportStorage'; + _.localStorage.set(key, val); + if (_.localStorage.get(key) !== val) { + supported = false; + } + _.localStorage.remove(key); + } catch (err) { + supported = false; + } + return supported; + } + + }; + + _.sessionStorage = { + + isSupport: function() { + var supported = true; + + var key = '__sensorsdatasupport__'; + var val = 'testIsSupportStorage'; + try { + if (sessionStorage && sessionStorage.setItem) { + sessionStorage.setItem(key, val); + sessionStorage.removeItem(key, val); + supported = true; + } else { + supported = false; + } + } catch (e) { + supported = false; + } + return supported; + } + }; + + _.isSupportCors = function() { + if (typeof window.XMLHttpRequest === 'undefined') { + return false; + } + if ('withCredentials' in new XMLHttpRequest()) { + return true; + } else if (typeof XDomainRequest !== "undefined") { + return true; + } else { + return false; + } + }; + + _.xhr = function(cors) { + if (cors) { + if (typeof window.XMLHttpRequest !== 'undefined' && ("withCredentials" in new XMLHttpRequest())) { + return new XMLHttpRequest(); + } else if (typeof XDomainRequest !== "undefined") { + return new XDomainRequest(); + } else { + return null; + } + } else { + if (typeof window.XMLHttpRequest !== 'undefined') { + return new XMLHttpRequest(); + } + if (window.ActiveXObject) { + try { + return new ActiveXObject('Msxml2.XMLHTTP') + } catch (d) { + try { + return new ActiveXObject('Microsoft.XMLHTTP') + } catch (d) { + sd.log(d); + + } + } + } + } + }; + + + _.ajax = function(para) { + para.timeout = para.timeout || 20000; + + para.credentials = (typeof para.credentials) === 'undefined' ? true : para.credentials; + + function getJSON(data) { + if (!data) { + return ''; + } + try { + return JSON.parse(data); + } catch (e) { + return {}; + } + } + + var g = _.xhr(para.cors); + + if (!g) { + return false; + } + + if (!para.type) { + para.type = para.data ? 'POST' : 'GET'; + } + para = _.extend({ + success: function() {}, + error: function() {} + }, para); + + try { + if (typeof g === 'object' && ('timeout' in g)) { + g.timeout = para.timeout; + } else { + setTimeout(function() { + g.abort(); + }, para.timeout + 500); + } + } catch (e) { + try { + setTimeout(function() { + g.abort(); + }, para.timeout + 500); + } catch (e2) { + sd.log(e2); + + }; + }; + + g.onreadystatechange = function() { + try { + if (g.readyState == 4) { + if ((g.status >= 200 && g.status < 300) || g.status == 304) { + para.success(getJSON(g.responseText)); + } else { + para.error(getJSON(g.responseText), g.status); + } + g.onreadystatechange = null; + g.onload = null; + } + } catch (e) { + g.onreadystatechange = null; + g.onload = null; + }; + + }; + + g.open(para.type, para.url, true); + + try { + if (para.credentials) { + g.withCredentials = true; + } + if (_.isObject(para.header)) { + for (var i in para.header) { + g.setRequestHeader(i, para.header[i]); + } + } + + if (para.data) { + if (!para.cors) { + g.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + } + if (para.contentType === 'application/json') { + g.setRequestHeader("Content-type", "application/json; charset=UTF-8"); + } else { + g.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); + } + + } + } catch (e) { + sd.log(e); + + }; + + g.send(para.data || null); + + }; + + _.loadScript = function(para) { + para = _.extend({ + success: function() {}, + error: function() {}, + appendCall: function(g) { + document.getElementsByTagName('head')[0].appendChild(g); + } + }, para); + + var g = null; + if (para.type === 'css') { + g = document.createElement('link'); + g.rel = 'stylesheet'; + g.href = para.url; + } + if (para.type === 'js') { + g = document.createElement('script'); + g.async = 'async'; + g.setAttribute('charset', 'UTF-8'); + g.src = para.url; + g.type = 'text/javascript'; + } + g.onload = g.onreadystatechange = function() { + if (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') { + para.success(); + g.onload = g.onreadystatechange = null; + } + }; + g.onerror = function() { + para.error(); + g.onerror = null; + }; + para.appendCall(g); + }; + + _.getHostname = function(url, defaultValue) { + if (!defaultValue || typeof defaultValue !== "string") { + defaultValue = "hostname解析异常"; + } + var hostname = null; + try { + hostname = _.URL(url).hostname; + } catch (e) { + sd.log(e); + + } + return hostname || defaultValue; + }; + + _.getQueryParamsFromUrl = function(url) { + var result = {}; + var arr = url.split('?'); + var queryString = arr[1] || ''; + if (queryString) { + result = _.getURLSearchParams('?' + queryString); + } + return result; + }; + + _.getURLSearchParams = function(queryString) { + queryString = queryString || ""; + var decodeParam = function(str) { + return decodeURIComponent(str); + }; + var args = {}; + var query = queryString.substring(1); + var pairs = query.split("&"); + for (var i = 0; i < pairs.length; i++) { + var pos = pairs[i].indexOf('='); + if (pos === -1) continue; + var name = pairs[i].substring(0, pos); + var value = pairs[i].substring(pos + 1); + name = decodeParam(name); + value = decodeParam(value); + args[name] = value; + } + return args; + }; + + _.URL = function(url) { + var result = {}; + var basicProps = ['hash', 'host', 'hostname', 'href', 'origin', 'password', 'pathname', 'port', 'protocol', 'search', 'username']; + var isURLAPIWorking = function() { + var url; + try { + url = new URL('http://modernizr.com/'); + return url.href === 'http://modernizr.com/'; + } catch (e) { + return false; + } + }; + if (typeof window.URL === 'function' && isURLAPIWorking()) { + result = new URL(url); + if (!result.searchParams) { + result.searchParams = (function() { + var params = _.getURLSearchParams(result.search); + return { + get: function(searchParam) { + return params[searchParam]; + } + }; + })(); + } + } else { + var _regex = /^https?:\/\/.+/; + if (_regex.test(url) === false) { + throw 'Invalid URL'; + } + var link = document.createElement('a'); + link.href = url; + for (var i = basicProps.length - 1; i >= 0; i--) { + var prop = basicProps[i]; + result[prop] = link[prop]; + } + if (result.hostname && typeof result.pathname === "string" && result.pathname.indexOf('/') !== 0) { + result.pathname = '/' + result.pathname; + } + result.searchParams = (function() { + var params = _.getURLSearchParams(result.search); + return { + get: function(searchParam) { + return params[searchParam]; + } + }; + })(); + } + return result; + }; + + _.getCurrentDomain = function(url) { + var sdDomain = sd.para.current_domain; + switch (typeof(sdDomain)) { + case "function": + var resultDomain = sdDomain(); + if (resultDomain === "" || _.trim(resultDomain) === "") { + return 'url解析失败'; + } else if (resultDomain.indexOf(".") !== -1) { + return resultDomain; + } else { + return "url解析失败"; + } + case "string": + if (sdDomain === "" || _.trim(sdDomain) === "") { + return 'url解析失败'; + } else if (sdDomain.indexOf(".") !== -1) { + return sdDomain; + } else { + return "url解析失败"; + } + default: + var cookieTopLevelDomain = _.getCookieTopLevelDomain(); + if (url === '') { + return 'url解析失败'; + } else if (cookieTopLevelDomain === '') { + return 'url解析失败'; + } else { + return cookieTopLevelDomain; + } + } + }; + + _.getCookieTopLevelDomain = function(hostname) { + hostname = hostname || window.location.hostname; + var splitResult = hostname.split('.'); + if (_.isArray(splitResult) && splitResult.length >= 2 && !/^(\d+\.)+\d+$/.test(hostname)) { + var domainStr = '.' + splitResult.splice(splitResult.length - 1, 1); + while (splitResult.length > 0) { + domainStr = '.' + splitResult.splice(splitResult.length - 1, 1) + domainStr; + document.cookie = "sensorsdata_domain_test=true; path=/; domain=" + domainStr; + if (document.cookie.indexOf('sensorsdata_domain_test=true') !== -1) { + var now = new Date(); + now.setTime(now.getTime() - 1000); + document.cookie = "sensorsdata_domain_test=true; expires=" + now.toGMTString() + "; path=/; domain=" + domainStr; + return domainStr; + } + } + } + return ''; + }; + + _.isReferralTraffic = function(refererstring) { + refererstring = refererstring || document.referrer; + if (refererstring === "") { + return true; + } + + return _.getCookieTopLevelDomain(_.getHostname(refererstring)) !== _.getCookieTopLevelDomain(); + }; + + + _.ry = function(dom) { + return new _.ry.init(dom); + }; + _.ry.init = function(dom) { + this.ele = dom; + }; + _.ry.init.prototype = { + addClass: function(para) { + var classes = ' ' + this.ele.className + ' '; + if (classes.indexOf(' ' + para + ' ') === -1) { + this.ele.className = this.ele.className + (this.ele.className === '' ? '' : ' ') + para; + } + return this; + }, + removeClass: function(para) { + var classes = ' ' + this.ele.className + ' '; + if (classes.indexOf(' ' + para + ' ') !== -1) { + this.ele.className = classes.replace(' ' + para + ' ', ' ').slice(1, -1); + } + return this; + }, + hasClass: function(para) { + var classes = ' ' + this.ele.className + ' '; + if (classes.indexOf(' ' + para + ' ') !== -1) { + return true; + } else { + return false; + } + }, + attr: function(key, value) { + if (typeof key === 'string' && _.isUndefined(value)) { + return this.ele.getAttribute(key); + } + if (typeof key === 'string') { + value = String(value); + this.ele.setAttribute(key, value); + } + return this; + }, + offset: function() { + var rect = this.ele.getBoundingClientRect(); + if (rect.width || rect.height) { + var doc = this.ele.ownerDocument; + var docElem = doc.documentElement; + + return { + top: rect.top + window.pageYOffset - docElem.clientTop, + left: rect.left + window.pageXOffset - docElem.clientLeft + }; + } else { + return { + top: 0, + left: 0 + } + } + + }, + getSize: function() { + if (!window.getComputedStyle) { + return { + width: this.ele.offsetWidth, + height: this.ele.offsetHeight + }; + } + try { + var bounds = this.ele.getBoundingClientRect(); + return { + width: bounds.width, + height: bounds.height + }; + } catch (e) { + return { + width: 0, + height: 0 + }; + } + }, + getStyle: function(value) { + if (this.ele.currentStyle) { + return this.ele.currentStyle[value]; + } else { + return this.ele.ownerDocument.defaultView.getComputedStyle(this.ele, null).getPropertyValue(value); + } + }, + wrap: function(elementTagName) { + var ele = document.createElement(elementTagName); + this.ele.parentNode.insertBefore(ele, this.ele); + ele.appendChild(this.ele); + return _.ry(ele); + }, + getCssStyle: function(prop) { + var result = this.ele.style.getPropertyValue(prop); + if (result) { + return result; + } + var rules = null; + if (typeof window.getMatchedCSSRules === 'function') { + rules = getMatchedCSSRules(this.ele); + } + if (!rules || !_.isArray(rules)) { + return null; + } + for (var i = rules.length - 1; i >= 0; i--) { + var r = rules[i]; + result = r.style.getPropertyValue(prop); + if (result) { + return result; + } + } + }, + sibling: function(cur, dir) { + while ((cur = cur[dir]) && cur.nodeType !== 1) {} + return cur; + }, + next: function() { + return this.sibling(this.ele, "nextSibling"); + }, + prev: function(elem) { + return this.sibling(this.ele, "previousSibling"); + }, + siblings: function(elem) { + return this.siblings((this.ele.parentNode || {}).firstChild, this.ele); + }, + children: function(elem) { + return this.siblings(this.ele.firstChild); + }, + parent: function() { + var parent = this.ele.parentNode; + parent = parent && parent.nodeType !== 11 ? parent : null; + return _.ry(parent); + } + }; + + _.strToUnicode = function(str) { + if (typeof str !== 'string') { + sd.log('转换unicode错误', str); + return str; + } + var nstr = ''; + for (var i = 0; i < str.length; i++) { + nstr += '\\' + str.charCodeAt(i).toString(16); + } + return nstr; + }; + + + _.getReferrer = function(referrer) { + var referrer = referrer || document.referrer; + if (typeof referrer !== 'string') { + return '取值异常_referrer异常_' + String(referrer); + } + if (referrer.indexOf("https://www.baidu.com/") === 0) { + referrer = referrer.split('?')[0]; + } + referrer = referrer.slice(0, sd.para.max_referrer_string_length); + return (typeof referrer === 'string' ? referrer : ''); + }; + + _.getKeywordFromReferrer = function(referrerUrl) { + referrerUrl = referrerUrl || document.referrer; + var search_keyword = sd.para.source_type.keyword; + if (document && typeof referrerUrl === 'string') { + if (referrerUrl.indexOf('http') === 0) { + var searchEngine = _.getReferSearchEngine(referrerUrl); + var query = _.getQueryParamsFromUrl(referrerUrl); + if (_.isEmptyObject(query)) { + return '未取到值'; + } + var temp = null; + for (var i in search_keyword) { + if (searchEngine === i) { + if (typeof query === 'object') { + temp = search_keyword[i]; + if (_.isArray(temp)) { + for (var i = 0; i < temp.length; i++) { + var _value = query[temp[i]]; + if (_value) { + return _value; + } + } + } else if (query[temp]) { + return query[temp]; + } + } + } + } + return '未取到值'; + } else { + if (referrerUrl === '') { + return '未取到值_直接打开'; + } else { + return '未取到值_非http的url'; + } + } + } else { + return '取值异常_referrer异常_' + String(referrerUrl); + } + }; + + _.getReferSearchEngine = function(referrerUrl) { + var hostname = _.getHostname(referrerUrl); + if (!hostname || hostname === 'hostname解析异常') { + return ''; + } + var search_keyword = sd.para.source_type.keyword; + var searchEngineUrls = { + baidu: [/^.*\.baidu\.com$/], + bing: [/^.*\.bing\.com$/], + google: [/^www\.google\.com$/, /^www\.google\.com\.[a-z]{2}$/, /^www\.google\.[a-z]{2}$/], + sm: [/^m\.sm\.cn$/], + so: [/^.+\.so\.com$/], + sogou: [/^.*\.sogou\.com$/], + yahoo: [/^.*\.yahoo\.com$/] + }; + for (var prop in searchEngineUrls) { + var urls = searchEngineUrls[prop]; + for (var i = 0, len = urls.length; i < len; i++) { + if (urls[i].test(hostname)) { + return prop; + } + } + } + return '未知搜索引擎'; + }; + + _.getSourceFromReferrer = function() { + function getMatchStrFromArr(arr, str) { + for (var i = 0; i < arr.length; i++) { + if (str.split('?')[0].indexOf(arr[i]) !== -1) { + return true; + } + } + } + + var utm_reg = '(' + sd.para.source_type.utm.join('|') + ')\\=[^&]+'; + var search_engine = sd.para.source_type.search; + var social_engine = sd.para.source_type.social; + + var referrer = document.referrer || ''; + var url = _.info.pageProp.url; + if (url) { + var utm_match = url.match(new RegExp(utm_reg)); + if (utm_match && utm_match[0]) { + return '付费广告流量'; + } else if (getMatchStrFromArr(search_engine, referrer)) { + return '自然搜索流量'; + } else if (getMatchStrFromArr(social_engine, referrer)) { + return '社交网站流量'; + } else if (referrer === '') { + return '直接流量'; + } else { + return '引荐流量'; + } + } else { + return '获取url异常'; + } + }; + + _.info = { + initPage: function() { + var referrer = _.getReferrer(); + var url = location.href; + var url_domain = _.getCurrentDomain(url); + if (!url_domain) { + sd.debug.jssdkDebug('url_domain异常_' + url + '_' + url_domain); + } + + this.pageProp = { + referrer: referrer, + referrer_host: referrer ? _.getHostname(referrer) : "", + url: url, + url_host: _.getHostname(url, 'url_host取值异常'), + url_domain: url_domain + }; + + + }, + pageProp: {}, + + campaignParams: function() { + var campaign_keywords = sd.source_channel_standard.split(' '), + kw = '', + params = {}; + if (_.isArray(sd.para.source_channel) && sd.para.source_channel.length > 0) { + campaign_keywords = campaign_keywords.concat(sd.para.source_channel); + campaign_keywords = _.unique(campaign_keywords); + } + _.each(campaign_keywords, function(kwkey) { + kw = _.getQueryParam(location.href, kwkey); + if (kw.length) { + params[kwkey] = kw; + } + }); + + return params; + }, + campaignParamsStandard: function(prefix, prefix_add) { + prefix = prefix || ''; + prefix_add = prefix_add || ''; + var utms = _.info.campaignParams(); + var $utms = {}, + otherUtms = {}; + for (var i in utms) { + if ((' ' + sd.source_channel_standard + ' ').indexOf(' ' + i + ' ') !== -1) { + $utms[prefix + i] = utms[i]; + } else { + otherUtms[prefix_add + i] = utms[i]; + } + } + return { + $utms: $utms, + otherUtms: otherUtms + }; + }, + properties: function() { + return { + $screen_height: Number(screen.height) || 0, + $screen_width: Number(screen.width) || 0, + $lib: 'js', + $lib_version: String(sd.lib_version) + }; + }, + currentProps: {}, + register: function(obj) { + _.extend(_.info.currentProps, obj); + } + }; + + + + + _.autoExeQueue = function() { + var queue = { + items: [], + enqueue: function(val) { + this.items.push(val); + this.start(); + }, + dequeue: function() { + return this.items.shift(); + }, + getCurrentItem: function() { + return this.items[0]; + }, + isRun: false, + start: function() { + if (this.items.length > 0 && !this.isRun) { + this.isRun = true; + this.getCurrentItem().start(); + } + }, + close: function() { + this.dequeue(); + this.isRun = false; + this.start(); + } + }; + return queue; + }; + + + + _.trackLink = function(obj, event_name, event_prop) { + obj = obj || {}; + var link = null; + if (obj.ele) { + link = obj.ele; + } + if (obj.event) { + if (obj.target) { + link = obj.target; + } else { + link = obj.event.target; + } + } + + event_prop = event_prop || {}; + if (!link || (typeof link !== 'object')) { + return false; + } + if (!link.href || /^javascript/.test(link.href) || link.target || link.download || link.onclick) { + sd.track(event_name, event_prop); + return false; + } + + function linkFunc(e) { + e.stopPropagation(); + e.preventDefault(); + var hasCalled = false; + + function track_a_click() { + if (!hasCalled) { + hasCalled = true; + location.href = link.href; + } + } + setTimeout(track_a_click, 1000); + sd.track(event_name, event_prop, track_a_click); + } + if (obj.event) { + linkFunc(obj.event); + } + if (obj.ele) { + _.addEvent(obj.ele, 'click', function(e) { + linkFunc(e); + }); + } + }; + + _.eventEmitter = function() { + this._events = []; + this.pendingEvents = []; + } + + _.eventEmitter.prototype = { + emit: function(type) { + var args = [].slice.call(arguments, 1); + + _.each(this._events, function(val) { + if (val.type !== type) { + return; + } + val.callback.apply(val.context, args); + }) + }, + on: function(event, callback, context) { + if (typeof callback !== 'function') { + return; + } + this._events.push({ + type: event, + callback: callback, + context: context || this + }); + }, + tempAdd: function(event, data) { + if (!data || !event) { + return; + } + + this.pendingEvents.push({ + type: event, + data: data + }); + this.pendingEvents.length > 20 ? this.pendingEvents.shift() : null; + }, + isReady: function() { + var that = this; + this.tempAdd = this.emit; + + if (this.pendingEvents.length === 0) { + return; + } + _.each(this.pendingEvents, function(val) { + that.emit(val.type, val.data); + }) + + this.pendingEvents = []; + + } + + } + + + })(); + + + + + sd.para_default = { + preset_properties: { + latest_utm: true, + latest_traffic_source_type: true, + latest_search_keyword: true, + latest_referrer: true, + latest_referrer_host: false, + latest_landing_page: false, + url: false, + title: false + }, + img_use_crossorigin: false, + + name: 'sa', + max_referrer_string_length: 200, + max_string_length: 500, + cross_subdomain: true, + show_log: true, + is_debug: false, + debug_mode: false, + debug_mode_upload: false, + + session_time: 0, + + use_client_time: false, + source_channel: [], + + send_type: 'image', + + vtrack_ignore: {}, + + auto_init: true, + + is_track_single_page: false, + + is_single_page: false, + + batch_send: false, + + source_type: {}, + callback_timeout: 200, + datasend_timeout: 3000, + queue_timeout: 300, + is_track_device_id: false, + ignore_oom: true, + app_js_bridge: false + }; + + sd.addReferrerHost = function(data) { + var defaultHost = "取值异常"; + if (_.isObject(data.properties)) { + if (data.properties.$first_referrer) { + data.properties.$first_referrer_host = _.getHostname(data.properties.$first_referrer, defaultHost); + } + if (data.type === "track" || data.type === "track_signup") { + if ('$referrer' in data.properties) { + data.properties.$referrer_host = data.properties.$referrer === "" ? "" : _.getHostname(data.properties.$referrer, defaultHost); + } + if (sd.para.preset_properties.latest_referrer && sd.para.preset_properties.latest_referrer_host) { + data.properties.$latest_referrer_host = data.properties.$latest_referrer === "" ? "" : _.getHostname(data.properties.$latest_referrer, defaultHost); + } + } + } + }; + + sd.addPropsHook = function(data) { + if (sd.para.preset_properties && sd.para.preset_properties.url && (data.type === "track" || data.type === "track_signup") && typeof data.properties.$url === 'undefined') { + data.properties.$url = window.location.href; + } + if (sd.para.preset_properties && sd.para.preset_properties.title && (data.type === "track" || data.type === "track_signup") && typeof data.properties.$title === 'undefined') { + data.properties.$title = document.title; + } + }; + + sd.initPara = function(para) { + sd.para = para || sd.para || {}; + var latestObj = {}; + if (_.isObject(sd.para.is_track_latest)) { + for (var latestProp in sd.para.is_track_latest) { + latestObj['latest_' + latestProp] = sd.para.is_track_latest[latestProp]; + } + } + + sd.para.preset_properties = _.extend({}, sd.para_default.preset_properties, latestObj, sd.para.preset_properties || {}); + + var app_js_bridge_default = { + is_send: true, + white_list: [], + H5verify: false, + }; + if (sd.para.use_app_track === true || sd.para.app_js_bridge === true) { + if (sd.para.use_app_track_is_send === false) { + sd.para.app_js_bridge_default.is_send = false; + } + sd.para.app_js_bridge = _.extend({}, app_js_bridge_default); + } else if (typeof sd.para.app_js_bridge === 'object') { + sd.para.app_js_bridge = _.extend({}, app_js_bridge_default, sd.para.app_js_bridge); + } else if (sd.para.use_app_track === 'only' || sd.para.use_app_track === 'mui') { + sd.para.app_js_bridge = sd.para.use_app_track; + } + + function initAppH5Status() { + function checkProjectAndHost(appUrl) { + function getHostNameAndProject(url) { + var obj = { + hostname: '', + project: '' + }; + try { + obj.hostname = _.URL(url).hostname; + obj.project = _.URL(url).searchParams.get('project') || 'default'; + } catch (e) { + console.log(e); + } + return obj; + } + var appObj = getHostNameAndProject(appUrl); + var H5Obj = getHostNameAndProject(sd.para.server_url); + if (appObj.hostname === H5Obj.hostname && appObj.project === H5Obj.project) { + return true; + } else { + if (sd.para.app_js_bridge.white_list[0]) { + for (var i = 0; i < sd.para.app_js_bridge.white_list.length; i++) { + var urlobj = getHostNameAndProject(sd.para.app_js_bridge.white_list[i]); + if (urlobj.hostname === appObj.hostname && urlobj.project === appObj.project) { + return true; + } + } + } + } + return false; + } + if (_.isObject(sd.para.app_js_bridge)) { + if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.sensorsdataNativeTracker && _.isObject(window.SensorsData_iOS_JS_Bridge) && window.SensorsData_iOS_JS_Bridge.sensorsdata_app_server_url) { + if (checkProjectAndHost(window.SensorsData_iOS_JS_Bridge.sensorsdata_app_server_url)) { + sd.para.app_js_bridge.H5verify = true; + }else{ + sd.para.app_js_bridge.defineModeDebugInfo = '4' + } + + } else if (_.isObject(window.SensorsData_APP_New_H5_Bridge) && window.SensorsData_APP_New_H5_Bridge.sensorsdata_get_server_url && window.SensorsData_APP_New_H5_Bridge.sensorsdata_track) { + var app_server_url = window.SensorsData_APP_New_H5_Bridge.sensorsdata_get_server_url(); + if (app_server_url) { + if (checkProjectAndHost(app_server_url)) { + sd.para.app_js_bridge.H5verify = true; + }else{ + sd.para.app_js_bridge.defineModeDebugInfo = '4' + } + } + + } else {} + } else {} + } + initAppH5Status(); + var i; + for (i in sd.para_default) { + if (sd.para[i] === void 0) { + sd.para[i] = sd.para_default[i]; + } + } + if (typeof sd.para.server_url === 'string' && sd.para.server_url.slice(0, 3) === '://') { + sd.para.server_url = location.protocol.slice(-1) + sd.para.server_url; + } + if (typeof sd.para.web_url === 'string' && sd.para.web_url.slice(0, 3) === '://') { + sd.para.web_url = location.protocol.slice(-1) + sd.para.web_url; + } + + if (sd.para.send_type !== 'image' && sd.para.send_type !== 'ajax' && sd.para.send_type !== 'beacon') { + sd.para.send_type = 'image'; + } + + var batch_send_default = { + datasend_timeout: 6000, + send_interval: 6000, + one_send_max_length: 6 + }; + + if (_.localStorage.isSupport() && _.isSupportCors() && typeof localStorage === 'object') { + if (sd.para.batch_send === true) { + sd.para.batch_send = _.extend({}, batch_send_default); + sd.para.use_client_time = true; + } else if (typeof sd.para.batch_send === 'object') { + sd.para.use_client_time = true; + sd.para.batch_send = _.extend({}, batch_send_default, sd.para.batch_send); + } + } else { + sd.para.batch_send = false; + } + + + var utm_type = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term']; + var search_type = ['www.baidu.', 'm.baidu.', 'm.sm.cn', 'so.com', 'sogou.com', 'youdao.com', 'google.', 'yahoo.com/', 'bing.com/', 'ask.com/']; + var social_type = ['weibo.com', 'renren.com', 'kaixin001.com', 'douban.com', 'qzone.qq.com', 'zhihu.com', 'tieba.baidu.com', 'weixin.qq.com']; + var search_keyword = { + baidu: ['wd', 'word', 'kw', 'keyword'], + google: 'q', + bing: 'q', + yahoo: 'p', + sogou: ['query', 'keyword'], + so: 'q', + sm: 'q' + }; + + if (typeof sd.para.source_type === 'object') { + sd.para.source_type.utm = _.isArray(sd.para.source_type.utm) ? sd.para.source_type.utm.concat(utm_type) : utm_type; + sd.para.source_type.search = _.isArray(sd.para.source_type.search) ? sd.para.source_type.search.concat(search_type) : search_type; + sd.para.source_type.social = _.isArray(sd.para.source_type.social) ? sd.para.source_type.social.concat(social_type) : social_type; + sd.para.source_type.keyword = _.isObject(sd.para.source_type.keyword) ? _.extend(search_keyword, sd.para.source_type.keyword) : search_keyword; + } + + if (_.isObject(sd.para.heatmap)) { + sd.para.heatmap.clickmap = sd.para.heatmap.clickmap || 'default'; + sd.para.heatmap.scroll_notice_map = sd.para.heatmap.scroll_notice_map || 'default'; + sd.para.heatmap.scroll_delay_time = sd.para.heatmap.scroll_delay_time || 4000; + sd.para.heatmap.scroll_event_duration = sd.para.heatmap.scroll_event_duration || 18000; + sd.para.heatmap.renderRefreshTime = sd.para.heatmap.renderRefreshTime || 1000; + sd.para.heatmap.loadTimeout = sd.para.heatmap.loadTimeout || 1000; + } + if (typeof sd.para.server_url === 'object' && sd.para.server_url.length) { + for (i = 0; i < sd.para.server_url.length; i++) { + if (!/sa\.gif[^\/]*$/.test(sd.para.server_url[i])) { + sd.para.server_url[i] = sd.para.server_url[i].replace(/\/sa$/, '/sa.gif').replace(/(\/sa)(\?[^\/]+)$/, '/sa.gif$2'); + } + } + } else if (!/sa\.gif[^\/]*$/.test(sd.para.server_url)) { + sd.para.server_url = sd.para.server_url.replace(/\/sa$/, '/sa.gif').replace(/(\/sa)(\?[^\/]+)$/, '/sa.gif$2'); + } + if (typeof sd.para.server_url === 'string') { + sd.para.debug_mode_url = sd.para.debug_mode_url || sd.para.server_url.replace('sa.gif', 'debug'); + } + if (sd.para.noCache === true) { + sd.para.noCache = '?' + (new Date()).getTime(); + } else { + sd.para.noCache = ''; + } + + if (sd.para.callback_timeout > sd.para.datasend_timeout) { + sd.para.datasend_timeout = sd.para.callback_timeout; + } + if (sd.para.callback_timeout > sd.para.queue_timeout) { + sd.para.queue_timeout = sd.para.callback_timeout; + } + if (sd.para.queue_timeout > sd.para.datasend_timeout) { + sd.para.datasend_timeout = sd.para.queue_timeout; + } + + }; + + + sd.readyState = { + state: 0, + historyState: [], + stateType: { + '1': '1-init未开始', + '2': '2-init开始', + '3': '3-store完成' + }, + getState: function() { + return this.historyState.join('\n'); + }, + setState: function(n) { + if (String(n) in this.stateType) { + this.state = n; + } + this.historyState.push(this.stateType[n]); + } + }; + + + sd.setPreConfig = function(sa) { + sd.para = sa.para; + sd._q = sa._q; + }; + + + sd.setInitVar = function() { + sd._t = sd._t || 1 * new Date(); + sd.lib_version = '1.15.1'; + sd.is_first_visitor = false; + sd.source_channel_standard = 'utm_source utm_medium utm_campaign utm_content utm_term'; + }; + + sd.log = function() { + if ((_.sessionStorage.isSupport() && sessionStorage.getItem('sensorsdata_jssdk_debug') === 'true') || sd.para.show_log) { + + if (sd.para.show_log === true || sd.para.show_log === 'string' || sd.para.show_log === false) { + arguments[0] = _.formatJsonString(arguments[0]); + } + + if (typeof console === 'object' && console.log) { + try { + return console.log.apply(console, arguments); + } catch (e) { + console.log(arguments[0]); + } + } + } + }; + + sd.enableLocalLog = function() { + if (_.sessionStorage.isSupport()) { + try { + sessionStorage.setItem('sensorsdata_jssdk_debug', 'true'); + } catch (e) { + sd.log('enableLocalLog error: ' + e.message); + } + } + }; + + sd.disableLocalLog = function() { + if (_.sessionStorage.isSupport()) { + sessionStorage.removeItem('sensorsdata_jssdk_debug'); + } + }; + + sd.debug = { + distinct_id: function() {}, + jssdkDebug: function() {}, + _sendDebug: function(debugString) { + sd.track('_sensorsdata2019_debug', { + _jssdk_debug_info: debugString + }); + }, + apph5: function(obj) { + var name = 'app_h5打通失败-'; + var relation = { + '1': name + 'use_app_track为false', + '2': name + 'Android或者iOS,没有暴露相应方法', + '3.1': name + 'Android校验server_url失败', + '3.2': name + 'iOS校验server_url失败', + '4.1': name + 'H5 校验 iOS server_url 失败', + '4.2': name + 'H5 校验 Android server_url 失败', + '4.3': name + 'H5 数据成功发往 Android', + '4.4': name + 'H5 数据成功发往 iOS' + }; + var output = obj.output; + var step = obj.step; + var data = obj.data || ''; + if (output === 'all' || output === 'console') { + sd.log(relation[step]); + } + if ((output === 'all' || output === 'code') && _.isObject(sd.para.is_debug) && sd.para.is_debug.apph5) { + if (!data.type || data.type.slice(0, 7) !== 'profile') { + data.properties._jssdk_debug_info = 'apph5-' + String(step); + } + } + }, + defineMode: function(type){ + var debugList = { + '1': { + "title": "当前页面无法进行可视化全埋点", + "message": "App SDK 与 Web SDK 没有进行打通,请联系贵方技术人员修正 App SDK 的配置,详细信息请查看文档。", + "link_text": "配置文档", + "link_url": "https://manual.sensorsdata.cn/sa/latest/app-h5-1573913.html" + }, + '2': { + "title": "当前页面无法进行可视化全埋点", + "message": "App SDK 与 Web SDK 没有进行打通,请联系贵方技术人员修正 Web SDK 的配置,详细信息请查看文档。", + "link_text": "配置文档", + "link_url": "https://manual.sensorsdata.cn/sa/latest/app-h5-1573913.html" + }, + '3': { + "title": "当前页面无法进行可视化全埋点", + "message": "Web SDK 没有开启全埋点配置,请联系贵方工作人员修正 SDK 的配置,详细信息请查看文档。", + "link_text": "配置文档", + "link_url": "https://manual.sensorsdata.cn/sa/latest/app-h5-1573913.html" + }, + '4': { + "title": "当前页面无法进行可视化全埋点", + "message": "Web SDK 配置的数据校验地址与 App SDK 配置的数据校验地址不一致,请联系贵方工作人员修正 SDK 的配置,详细信息请查看文档。", + "link_text": "配置文档", + "link_url": "https://manual.sensorsdata.cn/sa/latest/app-h5-1573913.html" + } + }; + if(type && debugList[type]){ + return debugList[type]; + }else{ + return false; + } + } + }; + + var commonWays = { + setOnlineState: function(state) { + if (state === true && _.isObject(sd.para.jsapp) && typeof sd.para.jsapp.getData === 'function') { + sd.para.jsapp.isOnline = true; + var arr = sd.para.jsapp.getData(); + if (_.isArray(arr) && arr.length > 0) { + _.each(arr, function(str) { + if (_.isJSONString(str)) { + sd.sendState.pushSend(JSON.parse(str)); + } + }); + } + } else { + sd.para.jsapp.isOnline = false; + } + }, + autoTrackIsUsed: false, + isReady: function(callback) { + callback(); + }, + getUtm: function() { + return _.info.campaignParams(); + }, + getStayTime: function() { + return ((new Date()) - sd._t) / 1000; + }, + setProfileLocal: function(obj) { + if (!_.localStorage.isSupport()) { + sd.setProfile(obj); + return false; + } + if (!_.isObject(obj) || _.isEmptyObject(obj)) { + return false; + } + var saveData = _.localStorage.parse('sensorsdata_2015_jssdk_profile'); + var isNeedSend = false; + if (_.isObject(saveData) && !_.isEmptyObject(saveData)) { + for (var i in obj) { + if ((i in saveData && saveData[i] !== obj[i]) || !(i in saveData)) { + saveData[i] = obj[i]; + isNeedSend = true; + } + } + if (isNeedSend) { + _.localStorage.set('sensorsdata_2015_jssdk_profile', JSON.stringify(saveData)); + sd.setProfile(obj); + } + } else { + _.localStorage.set('sensorsdata_2015_jssdk_profile', JSON.stringify(obj)); + sd.setProfile(obj); + } + }, + setInitReferrer: function() { + var _referrer = _.getReferrer(); + sd.setOnceProfile({ + _init_referrer: _referrer, + _init_referrer_host: _.info.pageProp.referrer_host + }); + }, + setSessionReferrer: function() { + var _referrer = _.getReferrer(); + store.setSessionPropsOnce({ + _session_referrer: _referrer, + _session_referrer_host: _.info.pageProp.referrer_host + }); + }, + setDefaultAttr: function() { + _.info.register({ + _current_url: location.href, + _referrer: _.getReferrer(), + _referring_host: _.info.pageProp.referrer_host + }); + }, + trackHeatMap: function(target, props, callback) { + if ((typeof target === 'object') && target.tagName) { + var tagName = target.tagName.toLowerCase(); + var parent_ele = target.parentNode.tagName.toLowerCase(); + if (tagName !== 'button' && tagName !== 'a' && parent_ele !== 'a' && parent_ele !== 'button' && tagName !== 'input' && tagName !== 'textarea' && !_.hasAttribute(target, 'data-sensors-click')) { + heatmap.start(null, target, tagName, props, callback); + } + } + }, + trackAllHeatMap: function(target, props, callback) { + if ((typeof target === 'object') && target.tagName) { + var tagName = target.tagName.toLowerCase(); + heatmap.start(null, target, tagName, props, callback); + } + }, + autoTrackSinglePage: function(para, callback) { + if (this.autoTrackIsUsed) { + var url = _.info.pageProp.url; + } else { + var url = _.info.pageProp.referrer; + } + para = _.isObject(para) ? para : {}; + + para = _.isObject(para) ? para : {}; + + + function getUtm() { + var utms = _.info.campaignParams(); + var $utms = {}; + for (var i in utms) { + if ((' ' + sd.source_channel_standard + ' ').indexOf(' ' + i + ' ') !== -1) { + $utms['$' + i] = utms[i]; + } else { + $utms[i] = utms[i]; + } + } + return $utms; + } + + if (sd.is_first_visitor && !para.not_set_profile) { + sd.setOnceProfile(_.extend({ + $first_visit_time: new Date(), + $first_referrer: _.getReferrer(), + $first_browser_language: navigator.language || '取值异常', + $first_browser_charset: typeof document.charset === 'string' ? document.charset.toUpperCase() : '取值异常', + $first_traffic_source_type: _.getSourceFromReferrer(), + $first_search_keyword: _.getKeywordFromReferrer() + }, getUtm())); + sd.is_first_visitor = false; + } + if (para.not_set_profile) { + delete para.not_set_profile; + } + + + function closure(p, c) { + sd.track('$pageview', _.extend({ + $referrer: url, + $url: location.href, + $url_path: location.pathname, + $title: document.title + }, p, getUtm()), c); + url = location.href; + } + closure(para, callback); + this.autoTrackSinglePage = closure; + }, + autoTrackWithoutProfile: function(para, callback) { + para = _.isObject(para) ? para : {}; + this.autoTrack(_.extend(para, { + not_set_profile: true + }), callback); + }, + autoTrack: function(para, callback) { + para = _.isObject(para) ? para : {}; + + var utms = _.info.campaignParams(); + var $utms = {}; + for (var i in utms) { + if ((' ' + sd.source_channel_standard + ' ').indexOf(' ' + i + ' ') !== -1) { + $utms['$' + i] = utms[i]; + } else { + $utms[i] = utms[i]; + } + } + if (sd.is_first_visitor && !para.not_set_profile) { + sd.setOnceProfile(_.extend({ + $first_visit_time: new Date(), + $first_referrer: _.getReferrer(), + $first_browser_language: navigator.language || '取值异常', + $first_browser_charset: typeof document.charset === 'string' ? document.charset.toUpperCase() : '取值异常', + $first_traffic_source_type: _.getSourceFromReferrer(), + $first_search_keyword: _.getKeywordFromReferrer() + }, $utms)); + sd.is_first_visitor = false; + } + if (para.not_set_profile) { + delete para.not_set_profile; + } + + var current_page_url = location.href; + + if (sd.para.is_single_page) { + _.addHashEvent(function() { + var referrer = _.getReferrer(current_page_url); + sd.track('$pageview', _.extend({ + $referrer: referrer, + $url: location.href, + $url_path: location.pathname, + $title: document.title + }, $utms, para), callback); + current_page_url = location.href; + }); + } + + sd.track('$pageview', _.extend({ + $referrer: _.getReferrer(), + $url: location.href, + $url_path: location.pathname, + $title: document.title + }, $utms, para), callback); + this.autoTrackIsUsed = true; + }, + getAnonymousID: function() { + if (_.isEmptyObject(sd.store._state)) { + return '请先初始化SDK'; + } else { + return sd.store._state._first_id || sd.store._state.first_id || sd.store._state._distinct_id || sd.store._state.distinct_id; + } + }, + setPlugin: function(para) { + if (!_.isObject(para)) { + return false; + } + _.each(para, function(v, k) { + if (_.isFunction(v)) { + if (_.isObject(window.SensorsDataWebJSSDKPlugin) && window.SensorsDataWebJSSDKPlugin[k]) { + v(window.SensorsDataWebJSSDKPlugin[k]); + } else { + sd.log(k + '没有获取到,请查阅文档,调整' + k + '的引入顺序!') + } + } + }); + } + }; + + sd.quick = function() { + var arg = Array.prototype.slice.call(arguments); + var arg0 = arg[0]; + var arg1 = arg.slice(1); + if (typeof arg0 === 'string' && commonWays[arg0]) { + return commonWays[arg0].apply(commonWays, arg1); + } else if (typeof arg0 === 'function') { + arg0.apply(sd, arg1); + } else { + sd.log('quick方法中没有这个功能' + arg[0]); + } + }; + + + sd.track = function(e, p, c) { + if (saEvent.check({ + event: e, + properties: p + })) { + saEvent.send({ + type: 'track', + event: e, + properties: p + }, c); + } + }; + + sd.trackLink = function(link, event_name, event_prop) { + if (typeof link === 'object' && link.tagName) { + _.trackLink({ + ele: link + }, event_name, event_prop); + } else if (typeof link === 'object' && link.target && link.event) { + _.trackLink(link, event_name, event_prop); + } + }; + sd.trackLinks = function(link, event_name, event_prop) { + var ele = link; + event_prop = event_prop || {}; + if (!link || (typeof link !== 'object')) { + return false; + } + if (!link.href || /^javascript/.test(link.href) || link.target) { + return false; + } + _.addEvent(link, 'click', function(e) { + e.preventDefault(); + var hasCalled = false; + setTimeout(track_a_click, 1000); + + function track_a_click() { + if (!hasCalled) { + hasCalled = true; + location.href = link.href; + } + } + sd.track(event_name, event_prop, track_a_click); + }); + + }; + + + sd.setProfile = function(p, c) { + if (saEvent.check({ + propertiesMust: p + })) { + saEvent.send({ + type: 'profile_set', + properties: p + }, c); + } + }; + + sd.setOnceProfile = function(p, c) { + if (saEvent.check({ + propertiesMust: p + })) { + saEvent.send({ + type: 'profile_set_once', + properties: p + }, c); + } + }; + + sd.appendProfile = function(p, c) { + if (saEvent.check({ + propertiesMust: p + })) { + _.each(p, function(value, key) { + if (_.isString(value)) { + p[key] = [value]; + } else if (_.isArray(value)) { + p[key] = value; + } else { + delete p[key]; + sd.log('appendProfile属性的值必须是字符串或者数组'); + } + }); + if (!_.isEmptyObject(p)) { + saEvent.send({ + type: 'profile_append', + properties: p + }, c); + } + } + }; + sd.incrementProfile = function(p, c) { + var str = p; + if (_.isString(p)) { + p = {} + p[str] = 1; + } + + function isChecked(p) { + for (var i in p) { + if (!/-*\d+/.test(String(p[i]))) { + return false; + } + } + return true; + } + + if (saEvent.check({ + propertiesMust: p + })) { + if (isChecked(p)) { + saEvent.send({ + type: 'profile_increment', + properties: p + }, c); + } else { + sd.log('profile_increment的值只能是数字'); + } + } + }; + + sd.deleteProfile = function(c) { + saEvent.send({ + type: 'profile_delete' + }, c); + store.set('distinct_id', _.UUID()); + store.set('first_id', ''); + }; + sd.unsetProfile = function(p, c) { + var str = p; + var temp = {}; + if (_.isString(p)) { + p = []; + p.push(str); + } + if (_.isArray(p)) { + _.each(p, function(v) { + if (_.isString(v)) { + temp[v] = true; + } else { + sd.log('profile_unset给的数组里面的值必须时string,已经过滤掉', v); + } + }); + saEvent.send({ + type: 'profile_unset', + properties: temp + }, c); + } else { + sd.log('profile_unset的参数是数组'); + } + }; + sd.identify = function(id, isSave) { + if (typeof id === 'number') { + id = String(id); + } + var firstId = store.getFirstId(); + if (typeof id === 'undefined') { + var uuid = _.UUID(); + if (firstId) { + store.set('first_id', uuid); + } else { + store.set('distinct_id', uuid); + } + } else if (saEvent.check({ + distinct_id: id + })) { + if (isSave === true) { + if (firstId) { + store.set('first_id', id); + } else { + store.set('distinct_id', id); + } + } else { + if (firstId) { + store.change('first_id', id); + } else { + store.change('distinct_id', id); + } + } + + } else { + sd.log('identify的参数必须是字符串'); + } + }; + sd.trackSignup = function(id, e, p, c) { + if (saEvent.check({ + distinct_id: id, + event: e, + properties: p + })) { + var original_id = store.getFirstId() || store.getDistinctId(); + store.set('distinct_id', id); + saEvent.send({ + original_id: original_id, + distinct_id: id, + type: 'track_signup', + event: e, + properties: p + }, c); + } + }; + + sd.trackAbtest = function(t, g) {}; + + sd.registerPage = function(obj) { + if (saEvent.check({ + properties: obj + })) { + _.extend(_.info.currentProps, obj); + } else { + sd.log('register输入的参数有误'); + } + }; + + sd.clearAllRegister = function(arr) { + store.clearAllProps(arr); + }; + + sd.register = function(props) { + if (saEvent.check({ + properties: props + })) { + store.setProps(props); + } else { + sd.log('register输入的参数有误'); + } + }; + + sd.registerOnce = function(props) { + if (saEvent.check({ + properties: props + })) { + store.setPropsOnce(props); + } else { + sd.log('registerOnce输入的参数有误'); + } + }; + + sd.registerSession = function(props) { + if (saEvent.check({ + properties: props + })) { + store.setSessionProps(props); + } else { + sd.log('registerSession输入的参数有误'); + } + }; + + sd.registerSessionOnce = function(props) { + if (saEvent.check({ + properties: props + })) { + store.setSessionPropsOnce(props); + } else { + sd.log('registerSessionOnce输入的参数有误'); + } + }; + + sd.login = function(id, callback) { + if (typeof id === 'number') { + id = String(id); + } + if (saEvent.check({ + distinct_id: id + })) { + var firstId = store.getFirstId(); + var distinctId = store.getDistinctId(); + if (id !== distinctId) { + if (!firstId) { + store.set('first_id', distinctId); + } + sd.trackSignup(id, '$SignUp', {}, callback); + } else { + callback && callback(); + } + } else { + sd.log('login的参数必须是字符串'); + callback && callback(); + } + }; + + sd.logout = function(isChangeId) { + var firstId = store.getFirstId(); + if (firstId) { + store.set('first_id', ''); + if (isChangeId === true) { + var uuid = _.UUID(); + store.set('distinct_id', uuid); + } else { + store.set('distinct_id', firstId); + } + + } else { + sd.log('没有first_id,logout失败'); + } + }; + + sd.getPresetProperties = function() { + function getUtm() { + var utms = _.info.campaignParams(); + var $utms = {}; + for (var i in utms) { + if ((' ' + sd.source_channel_standard + ' ').indexOf(' ' + i + ' ') !== -1) { + $utms['$' + i] = utms[i]; + } else { + $utms[i] = utms[i]; + } + } + return $utms; + } + + var obj = { + $referrer: _.info.pageProp.referrer || '', + $referrer_host: _.info.pageProp.referrer ? _.getHostname(_.info.pageProp.referrer) : '', + $url: location.href, + $url_path: location.pathname, + $title: document.title || '', + _distinct_id: store.getDistinctId() + }; + var result = _.extend({}, _.info.properties(), sd.store.getProps(), getUtm(), obj); + if (sd.para.preset_properties.latest_referrer && sd.para.preset_properties.latest_referrer_host) { + result.$latest_referrer_host = result.$latest_referrer === "" ? "" : _.getHostname(result.$latest_referrer); + } + return result; + }; + + + + + + + + + + + + + + function BatchSend() { + this.sendingData = 0; + }; + + BatchSend.prototype = { + add: function(data) { + if (_.isObject(data)) { + this.writeStore(data); + if (data.type === 'track_signup' || data.event === '$pageview') { + this.sendStrategy(); + } + } + }, + remove: function(keys) { + var me = this; + if (this.sendingData > 0) { + --this.sendingData; + } + if (_.isArray(keys) && keys.length > 0) { + _.each(keys, function(key) { + _.localStorage.remove(key); + }); + } + }, + send: function(data) { + var me = this; + var server_url = _.isArray(sd.para.server_url) ? sd.para.server_url[0] : sd.para.server_url; + _.ajax({ + url: server_url, + type: 'POST', + data: 'data_list=' + encodeURIComponent(_.base64Encode(JSON.stringify(data.vals))), + credentials: false, + timeout: sd.para.batch_send.datasend_timeout, + cors: true, + success: function() { + me.remove(data.keys); + }, + error: function() { + if (me.sendingData > 0) { + --me.sendingData; + } + } + }); + + }, + sendPrepare: function(data) { + var arr = data.vals; + var maxLen = sd.para.batch_send.one_send_max_length; + var arrLen = arr.length; + if (arrLen > 0) { + if (arrLen <= maxLen) { + this.send({ + keys: data.keys, + vals: arr + }); + } else { + for (var i = 0; i * maxLen < arrLen; i++) { + this.send({ + keys: data.keys.splice(0, maxLen), + vals: arr.splice(0, maxLen) + }); + } + + } + } + }, + sendStrategy: function() { + var data = this.readStore(); + if (data.keys.length > 0 && this.sendingData === 0) { + this.sendingData = Math.ceil(data.vals.length / sd.para.batch_send.one_send_max_length) + this.sendPrepare(data); + } + }, + batchInterval: function() { + var me = this; + setInterval(function() { + me.sendStrategy(); + }, sd.para.batch_send.send_interval); + }, + readStore: function() { + var keys = []; + var vals = []; + var obj = {}; + var val = null; + var now = (new Date()).getTime(); + var len = localStorage.length; + for (var i = 0; i < len; i++) { + var key = localStorage.key(i); + if (key.indexOf('sawebjssdk-') === 0 && /^sawebjssdk\-\d+$/.test(key)) { + val = localStorage.getItem(key); + if (val) { + val = _.safeJSONParse(val); + if (val && _.isObject(val)) { + val._flush_time = now; + keys.push(key); + vals.push(val); + } else { + localStorage.removeItem(key); + sd.log('localStorage-数据parse异常' + val); + } + } else { + localStorage.removeItem(key); + sd.log('localStorage-数据取值异常' + val); + } + } + } + return { + keys: keys, + vals: vals + }; + }, + writeStore: function(data) { + var uuid = String(Math.random()).slice(2, 5) + String(Math.random()).slice(2, 5) + String((new Date()).getTime()).slice(3); + localStorage.setItem('sawebjssdk-' + uuid, JSON.stringify(data)); + } + }; + + sd.batchSend = new BatchSend(); + + + + + var dataSend = {}; + + dataSend.getSendUrl = function(url, data) { + var base64Data = _.base64Encode(data); + var crc = 'crc=' + _.hashCode(base64Data); + if (url.indexOf('?') !== -1) { + return url + '&data=' + encodeURIComponent(base64Data) + '&ext=' + encodeURIComponent(crc); + } else { + return url + '?data=' + encodeURIComponent(base64Data) + '&ext=' + encodeURIComponent(crc); + } + }; + + dataSend.getSendData = function(data) { + var base64Data = _.base64Encode(data); + var crc = 'crc=' + _.hashCode(base64Data); + return 'data=' + encodeURIComponent(base64Data) + '&ext=' + encodeURIComponent(crc); + }; + + + dataSend.getInstance = function(data) { + var sendType = this.getSendType(data); + var obj = new this[sendType](data); + var start = obj.start; + obj.start = function() { + if (_.isObject(sd.para.is_debug) && sd.para.is_debug.storage && sd.store.requests) { + sd.store.requests.push({ + name: this.server_url, + initiatorType: this.img ? 'img' : 'xmlhttprequest', + entryType: "resource", + requestData: this.data + }); + } + var me = this; + start.apply(this, arguments); + setTimeout(function() { + me.isEnd(true); + }, sd.para.callback_timeout); + }; + obj.end = function() { + this.callback && this.callback(); + var self = this; + setTimeout(function() { + self.lastClear && self.lastClear(); + }, sd.para.datasend_timeout - sd.para.callback_timeout); + }; + obj.isEnd = function(isDelay) { + if (!this.received) { + this.received = true; + this.end(); + var self = this; + if (isDelay) { + if (sd.para.queue_timeout - sd.para.callback_timeout <= 0) { + self.close(); + } else { + setTimeout(function() { + self.close(); + }, sd.para.queue_timeout - sd.para.callback_timeout); + } + } else { + self.close(); + } + } + }; + + return obj; + + }; + + dataSend.getSendType = function(data) { + var supportedSendTypes = ['image', 'ajax', 'beacon']; + var sendType = supportedSendTypes[0]; + + if (data.config && _.indexOf(supportedSendTypes, data.config.send_type) > -1) { + sendType = data.config.send_type; + } else { + sendType = sd.para.send_type; + } + + if (sendType === 'beacon' && typeof navigator.sendBeacon !== "function") { + sendType = 'image'; + } + + if (sendType === 'ajax' && _.isSupportCors() === false) { + sendType = 'image'; + } + + return sendType; + }; + + dataSend.image = function(para) { + this.callback = para.callback; + this.img = document.createElement('img'); + this.img.width = 1; + this.img.height = 1; + if (sd.para.img_use_crossorigin) { + this.img.crossOrigin = 'anonymous'; + } + this.data = para.data; + this.server_url = dataSend.getSendUrl(para.server_url, para.data); + }; + dataSend.image.prototype.start = function() { + var me = this; + if (sd.para.ignore_oom) { + this.img.onload = function() { + this.onload = null; + this.onerror = null; + this.onabort = null; + me.isEnd(); + }; + this.img.onerror = function() { + this.onload = null; + this.onerror = null; + this.onabort = null; + me.isEnd(); + }; + this.img.onabort = function() { + this.onload = null; + this.onerror = null; + this.onabort = null; + me.isEnd(); + }; + } + this.img.src = this.server_url; + }; + + dataSend.image.prototype.lastClear = function() { + this.img.src = ""; + } + + dataSend.ajax = function(para) { + this.callback = para.callback; + this.server_url = para.server_url; + this.data = dataSend.getSendData(para.data); + }; + dataSend.ajax.prototype.start = function() { + var me = this; + _.ajax({ + url: this.server_url, + type: 'POST', + data: this.data, + credentials: false, + timeout: sd.para.datasend_timeout, + cors: true, + success: function() { + me.isEnd(); + }, + error: function() { + me.isEnd(); + } + }); + }; + + dataSend.beacon = function(para) { + this.callback = para.callback; + this.server_url = para.server_url; + this.data = dataSend.getSendData(para.data); + }; + + dataSend.beacon.prototype.start = function() { + var me = this; + if (typeof navigator === 'object' && typeof navigator.sendBeacon === 'function') { + navigator.sendBeacon(this.server_url, this.data); + } + setTimeout(function() { + me.isEnd(); + }, 40); + }; + + + + + var sendState = {}; + sd.sendState = sendState; + sd.events = new _.eventEmitter(); + sendState.queue = _.autoExeQueue(); + + sendState.requestData = null; + + sendState.getSendCall = function(data, config, callback) { + if (sd.is_heatmap_render_mode) { + return false; + } + + if (sd.readyState.state < 3) { + sd.log('初始化没有完成'); + return false; + } + + data._track_id = Number(String(Math.random()).slice(2, 5) + String(Math.random()).slice(2, 4) + String((new Date()).getTime()).slice(-4)); + if (sd.para.use_client_time) { + data._flush_time = (new Date()).getTime(); + } + + var originData = data; + + data = JSON.stringify(data); + + this.requestData = { + data: originData, + config: config, + callback: callback + }; + + sd.events.tempAdd('send', originData); + + if (!sd.para.app_js_bridge && sd.para.batch_send && localStorage.length < 200) { + sd.log(originData); + sd.batchSend.add(this.requestData.data); + return false; + } + + if (_.isObject(sd.para.app_js_bridge) || sd.para.app_js_bridge === 'only') { + if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.sensorsdataNativeTracker && _.isObject(window.SensorsData_iOS_JS_Bridge) && window.SensorsData_iOS_JS_Bridge.sensorsdata_app_server_url) { + if (sd.para.app_js_bridge.H5verify) { + sd.debug.apph5({ + data: originData, + step: '4.4', + output: 'all' + }); + window.webkit.messageHandlers.sensorsdataNativeTracker.postMessage(JSON.stringify({ + callType: 'app_h5_track', + data: _.extend({ + server_url: sd.para.server_url + }, originData) + })); + } else { + if (sd.para.app_js_bridge.is_send) { + sd.debug.apph5({ + data: originData, + step: '4.1', + output: 'all' + }); + this.prepareServerUrl(); + } + + } + } else if (_.isObject(window.SensorsData_APP_New_H5_Bridge) && window.SensorsData_APP_New_H5_Bridge.sensorsdata_get_server_url && window.SensorsData_APP_New_H5_Bridge.sensorsdata_track) { + if (sd.para.app_js_bridge.H5verify) { + sd.debug.apph5({ + data: originData, + step: '4.3', + output: 'all' + }); + SensorsData_APP_New_H5_Bridge.sensorsdata_track(JSON.stringify(_.extend({ + server_url: sd.para.server_url + }, originData))); + } else { + if (sd.para.app_js_bridge.is_send) { + sd.debug.apph5({ + data: originData, + step: '4.2', + output: 'all' + }); + this.prepareServerUrl(); + } + + } + } else if ((typeof SensorsData_APP_JS_Bridge === 'object') && (SensorsData_APP_JS_Bridge.sensorsdata_verify || SensorsData_APP_JS_Bridge.sensorsdata_track)) { + if (SensorsData_APP_JS_Bridge.sensorsdata_verify) { + if (!SensorsData_APP_JS_Bridge.sensorsdata_verify(JSON.stringify(_.extend({ + server_url: sd.para.server_url + }, originData)))) { + if (sd.para.app_js_bridge.is_send) { + sd.debug.apph5({ + data: originData, + step: '3.1', + output: 'all' + }); + this.prepareServerUrl(); + } + } else { + (typeof callback === 'function') && callback(); + } + } else { + SensorsData_APP_JS_Bridge.sensorsdata_track(JSON.stringify(_.extend({ + server_url: sd.para.server_url + }, originData))); + (typeof callback === 'function') && callback(); + } + } else if ((/sensors-verify/.test(navigator.userAgent) || /sa-sdk-ios/.test(navigator.userAgent)) && !window.MSStream) { + var iframe = null; + if (/sensors-verify/.test(navigator.userAgent)) { + var match = navigator.userAgent.match(/sensors-verify\/([^\s]+)/); + if (match && match[0] && (typeof match[1] === 'string') && (match[1].split('?').length === 2)) { + match = match[1].split('?'); + var hostname = null; + var project = null; + try { + hostname = _.URL(sd.para.server_url).hostname; + project = _.URL(sd.para.server_url).searchParams.get('project') || 'default'; + } catch (e) { + sd.log(e); + }; + if (hostname && hostname === match[0] && project && project === match[1]) { + iframe = document.createElement('iframe'); + iframe.setAttribute('src', 'sensorsanalytics://trackEvent?event=' + encodeURIComponent(JSON.stringify(_.extend({ + server_url: sd.para.server_url + }, originData)))); + document.documentElement.appendChild(iframe); + iframe.parentNode.removeChild(iframe); + iframe = null; + (typeof callback === 'function') && callback(); + } else { + if (sd.para.app_js_bridge.is_send) { + sd.debug.apph5({ + data: originData, + step: '3.2', + output: 'all' + }); + this.prepareServerUrl(); + } + } + } + } else { + iframe = document.createElement('iframe'); + iframe.setAttribute('src', 'sensorsanalytics://trackEvent?event=' + encodeURIComponent(JSON.stringify(_.extend({ + server_url: sd.para.server_url + }, originData)))); + document.documentElement.appendChild(iframe); + iframe.parentNode.removeChild(iframe); + iframe = null; + (typeof callback === 'function') && callback(); + } + } else { + if (_.isObject(sd.para.app_js_bridge) && sd.para.app_js_bridge.is_send === true) { + sd.debug.apph5({ + data: originData, + step: '2', + output: 'all' + }); + this.prepareServerUrl(); + } + } + } else if (sd.para.app_js_bridge === 'mui') { + if (_.isObject(window.plus) && window.plus.SDAnalytics && window.plus.SDAnalytics.trackH5Event) { + window.plus.SDAnalytics.trackH5Event(data); + } + } else { + sd.debug.apph5({ + data: originData, + step: '1', + output: 'code' + }); + this.prepareServerUrl(); + } + sd.log(originData); + }; + + sendState.prepareServerUrl = function() { + if (typeof this.requestData.config === 'object' && this.requestData.config.server_url) { + this.sendCall(this.requestData.config.server_url, this.requestData.callback); + } else if (_.isArray(sd.para.server_url)) { + for (var i = 0; i < sd.para.server_url.length; i++) { + this.sendCall(sd.para.server_url[i]); + } + } else { + this.sendCall(sd.para.server_url, this.requestData.callback); + } + }; + + sendState.sendCall = function(server_url, callback) { + var data = { + server_url: server_url, + data: JSON.stringify(this.requestData.data), + callback: callback, + config: this.requestData.config + }; + if (_.isObject(sd.para.jsapp) && !sd.para.jsapp.isOnline && typeof sd.para.jsapp.setData === 'function') { + delete data.callback; + data = JSON.stringify(data); + sd.para.jsapp.setData(data); + } else { + this.pushSend(data); + } + }; + + sendState.pushSend = function(data) { + var instance = dataSend.getInstance(data); + var me = this; + instance.close = function() { + me.queue.close(); + }; + this.queue.enqueue(instance); + }; + + + var saEvent = {}; + + saEvent.checkOption = { + regChecks: { + regName: /^((?!^distinct_id$|^original_id$|^time$|^properties$|^id$|^first_id$|^second_id$|^users$|^events$|^event$|^user_id$|^date$|^datetime$)[a-zA-Z_$][a-zA-Z\d_$]{0,99})$/i + }, + checkPropertiesKey: function(obj) { + var me = this, + flag = true; + _.each(obj, function(content, key) { + if (!me.regChecks.regName.test(key)) { + flag = false; + } + }); + return flag; + }, + check: function(a, b) { + if (typeof this[a] === 'string') { + return this[this[a]](b); + } else { + return this[a](b); + } + }, + str: function(s) { + if (!_.isString(s)) { + sd.log('请检查参数格式,必须是字符串'); + return true; + } else { + return true; + } + }, + properties: function(p) { + _.strip_sa_properties(p); + if (p) { + if (_.isObject(p)) { + if (this.checkPropertiesKey(p)) { + return true; + } else { + sd.log('properties 里的自定义属性名需要是合法的变量名,不能以数字开头,且只包含:大小写字母、数字、下划线,自定义属性不能以 $ 开头'); + return true; + } + } else { + sd.log('properties可以没有,但有的话必须是对象'); + return true; + } + } else { + return true; + } + }, + propertiesMust: function(p) { + _.strip_sa_properties(p); + if (p === undefined || !_.isObject(p) || _.isEmptyObject(p)) { + sd.log('properties必须是对象且有值'); + return true; + } else { + if (this.checkPropertiesKey(p)) { + return true; + } else { + sd.log('properties 里的自定义属性名需要是合法的变量名,不能以数字开头,且只包含:大小写字母、数字、下划线,自定义属性不能以 $ 开头'); + return true; + } + } + }, + event: function(s) { + if (!_.isString(s) || !this['regChecks']['regName'].test(s)) { + sd.log('请检查参数格式,eventName 必须是字符串,且需是合法的变量名,即不能以数字开头,且只包含:大小写字母、数字、下划线和 $,其中以 $ 开头的表明是系统的保留字段,自定义事件名请不要以 $ 开头'); + return true; + } else { + return true; + } + + }, + test_id: 'str', + group_id: 'str', + distinct_id: function(id) { + if (_.isString(id) && /^.{1,255}$/.test(id)) { + return true; + } else { + sd.log('distinct_id必须是不能为空,且小于255位的字符串'); + return false; + } + } + }; + + saEvent.check = function(p) { + var flag = true; + for (var i in p) { + if (!this.checkOption.check(i, p[i])) { + return false; + } + } + return flag; + }; + + saEvent.send = function(p, callback) { + var data = { + distinct_id: store.getDistinctId(), + lib: { + $lib: 'js', + $lib_method: 'code', + $lib_version: String(sd.lib_version) + }, + properties: {} + }; + + if (_.isObject(p) && _.isObject(p.properties) && !_.isEmptyObject(p.properties) && p.properties.$lib_detail) { + data.lib.$lib_detail = p.properties.$lib_detail; + delete p.properties.$lib_detail; + } + _.extend(data, sd.store.getUnionId(), p); + + if (_.isObject(p.properties) && !_.isEmptyObject(p.properties)) { + _.extend(data.properties, p.properties); + } + + if (!p.type || p.type.slice(0, 7) !== 'profile') { + + data.properties = _.extend({}, _.info.properties(), store.getProps(), store.getSessionProps(), _.info.currentProps, data.properties); + if (sd.para.preset_properties.latest_referrer && !_.isString(data.properties.$latest_referrer)) { + data.properties.$latest_referrer = '取值异常'; + } + if (sd.para.preset_properties.latest_search_keyword && !_.isString(data.properties.$latest_search_keyword)) { + data.properties.$latest_search_keyword = '取值异常'; + } + if (sd.para.preset_properties.latest_traffic_source_type && !_.isString(data.properties.$latest_traffic_source_type)) { + data.properties.$latest_traffic_source_type = '取值异常'; + } + if (sd.para.preset_properties.latest_landing_page && !_.isString(data.properties.$latest_landing_page)) { + data.properties.$latest_landing_page = '取值异常'; + } + } + + if (data.properties.$time && _.isDate(data.properties.$time)) { + data.time = data.properties.$time * 1; + delete data.properties.$time; + } else { + if (sd.para.use_client_time) { + data.time = (new Date()) * 1; + } + } + _.parseSuperProperties(data.properties); + + _.filterReservedProperties(data.properties); + _.searchObjDate(data); + _.searchObjString(data); + _.searchZZAppStyle(data); + + var data_config = _.searchConfigData(data.properties); + + saNewUser.checkIsAddSign(data); + saNewUser.checkIsFirstTime(data); + + sd.addReferrerHost(data); + sd.addPropsHook(data); + + if (sd.para.debug_mode === true) { + sd.log(data); + this.debugPath(JSON.stringify(data), callback); + } else { + sd.sendState.getSendCall(data, data_config, callback); + } + + }; + + saEvent.debugPath = function(data, callback) { + var _data = data; + var url = ''; + if (sd.para.debug_mode_url.indexOf('?') !== -1) { + url = sd.para.debug_mode_url + '&data=' + encodeURIComponent(_.base64Encode(data)); + } else { + url = sd.para.debug_mode_url + '?data=' + encodeURIComponent(_.base64Encode(data)); + } + + _.ajax({ + url: url, + type: 'GET', + cors: true, + header: { + 'Dry-Run': String(sd.para.debug_mode_upload) + }, + success: function(data) { + _.isEmptyObject(data) === true ? alert('debug数据发送成功' + _data) : alert('debug失败 错误原因' + JSON.stringify(data)); + } + }); + + }; + + + var store = sd.store = { + requests: [], + _sessionState: {}, + _state: { + distinct_id: '', + first_id: '', + props: {} + }, + getProps: function() { + return this._state.props || {}; + }, + getSessionProps: function() { + return this._sessionState; + }, + getDistinctId: function() { + return this._state._distinct_id || this._state.distinct_id; + }, + getUnionId: function() { + var obj = {}; + var firstId = this._state._first_id || this._state.first_id, + distinct_id = this._state._distinct_id || this._state.distinct_id; + if (firstId && distinct_id) { + obj.login_id = distinct_id; + obj.anonymous_id = firstId; + } else { + obj.anonymous_id = distinct_id; + } + return obj; + }, + getFirstId: function() { + return this._state._first_id || this._state.first_id; + }, + toState: function(ds) { + var state = null; + if (ds != null && _.isJSONString(ds)) { + state = JSON.parse(ds); + this._state = _.extend(state); + if (state.distinct_id) { + if (typeof(state.props) === 'object') { + for (var key in state.props) { + if (typeof state.props[key] === 'string') { + state.props[key] = state.props[key].slice(0, sd.para.max_referrer_string_length); + } + } + this.save(); + } + + } else { + this.set('distinct_id', _.UUID()); + sd.debug.distinct_id('1', ds); + } + } else { + this.set('distinct_id', _.UUID()); + sd.debug.distinct_id('2', ds); + } + }, + initSessionState: function() { + var ds = _.cookie.get('sensorsdata2015session'); + var state = null; + if (ds !== null && (typeof(state = JSON.parse(ds)) === 'object')) { + this._sessionState = state || {}; + } + }, + + setOnce: function(a, b) { + if (!(a in this._state)) { + this.set(a, b); + } + }, + set: function(name, value) { + this._state = this._state || {}; + if (name === 'distinct_id' && this._state.distinct_id) { + sd.events.tempAdd('changeDistinctId', value); + } + this._state[name] = value; + if (name === 'first_id') { + delete this._state._first_id; + } else if (name === 'distinct_id') { + delete this._state._distinct_id; + } + this.save(); + + }, + change: function(name, value) { + this._state['_' + name] = value; + }, + setSessionProps: function(newp) { + var props = this._sessionState; + _.extend(props, newp); + this.sessionSave(props); + }, + setSessionPropsOnce: function(newp) { + var props = this._sessionState; + _.coverExtend(props, newp); + this.sessionSave(props); + }, + setProps: function(newp, isCover) { + var props = {}; + if (!isCover) { + props = _.extend((this._state.props || {}), newp); + } else { + props = newp; + } + for (var key in props) { + if (typeof props[key] === 'string') { + props[key] = props[key].slice(0, sd.para.max_referrer_string_length); + } + } + this.set('props', props); + }, + setPropsOnce: function(newp) { + var props = this._state.props || {}; + _.coverExtend(props, newp); + this.set('props', props); + }, + clearAllProps: function(arr) { + this._sessionState = {}; + if (_.isArray(arr) && arr.length > 0) { + for (var i = 0; i < arr.length; i++) { + if (_.isString(arr[i]) && arr[i].indexOf('latest_') === -1 && arr[i] in this._state.props) { + delete this._state.props[arr[i]]; + } + } + } else { + for (var i in this._state.props) { + if (i.indexOf('latest_') !== 1) { + delete this._state.props[i]; + } + } + } + this.sessionSave({}); + this.save(); + }, + sessionSave: function(props) { + this._sessionState = props; + _.cookie.set('sensorsdata2015session', JSON.stringify(this._sessionState), 0); + }, + save: function() { + var copyState = JSON.parse(JSON.stringify(this._state)); + delete copyState._first_id; + delete copyState._distinct_id; + _.cookie.set(this.getCookieName(), JSON.stringify(copyState), 73000, sd.para.cross_subdomain); + }, + getCookieName: function() { + var sub = ''; + if (sd.para.cross_subdomain === false) { + try { + sub = _.URL(location.href).hostname; + } catch (e) { + sd.log(e); + } + if (typeof sub === 'string' && sub !== '') { + sub = 'sa_jssdk_2015_' + sub.replace(/\./g, '_'); + } else { + sub = 'sa_jssdk_2015_root'; + } + } else { + sub = 'sensorsdata2015jssdkcross'; + } + return sub; + }, + init: function() { + + this.initSessionState(); + var uuid = _.UUID(); + var cross = _.cookie.get(this.getCookieName()); + if (cross === null) { + sd.is_first_visitor = true; + + this.set('distinct_id', uuid); + } else { + + if (!_.isJSONString(cross) || !(JSON.parse(cross)).distinct_id) { + sd.is_first_visitor = true; + } + + this.toState(cross); + } + + + saNewUser.setDeviceId(uuid); + + saNewUser.storeInitCheck(); + saNewUser.checkIsFirstLatest(); + + } + }; + + + var saNewUser = { + checkIsAddSign: function(data) { + if (data.type === 'track') { + if (_.cookie.getNewUser()) { + data.properties.$is_first_day = true; + } else { + data.properties.$is_first_day = false; + } + } + }, + is_first_visit_time: false, + checkIsFirstTime: function(data) { + if (data.type === 'track' && data.event === '$pageview') { + if (this.is_first_visit_time) { + data.properties.$is_first_time = true; + this.is_first_visit_time = false; + } else { + data.properties.$is_first_time = false; + } + } + }, + setDeviceId: function(uuid) { + var device_id = null; + var ds = _.cookie.get('sensorsdata2015jssdkcross'); + var state = {}; + if (ds != null && _.isJSONString(ds)) { + state = JSON.parse(ds); + if (state.$device_id) { + device_id = state.$device_id; + } + } + + device_id = device_id || uuid; + + if (sd.para.cross_subdomain === true) { + store.set('$device_id', device_id); + } else { + state.$device_id = device_id; + _.cookie.set('sensorsdata2015jssdkcross', JSON.stringify(state), null, true); + } + + if (sd.para.is_track_device_id) { + _.info.currentProps.$device_id = device_id; + } + + }, + storeInitCheck: function() { + if (sd.is_first_visitor) { + + var date = new Date(); + var obj = { + h: 23 - date.getHours(), + m: 59 - date.getMinutes(), + s: 59 - date.getSeconds() + }; + _.cookie.set(_.cookie.getCookieName('new_user'), '1', obj.h * 3600 + obj.m * 60 + obj.s + 's'); + this.is_first_visit_time = true; + } else { + if (!_.cookie.getNewUser()) { + this.checkIsAddSign = function(data) { + if (data.type === 'track') { + data.properties.$is_first_day = false; + } + }; + } + this.checkIsFirstTime = function(data) { + if (data.type === 'track' && data.event === '$pageview') { + data.properties.$is_first_time = false; + } + } + } + }, + checkIsFirstLatest: function() { + var url_domain = _.info.pageProp.url_domain; + + var latest_utms = ['$utm_source', '$utm_medium', '$utm_campaign', '$utm_content', '$utm_term']; + var props = store.getProps(); + for (var i = 0; i < latest_utms.length; i++) { + if (latest_utms[i] in props) { + delete props[latest_utms[i]]; + } + } + store.setProps(props, true); + + + + var latestObj = {}; + + if (url_domain === "") { + url_domain = "url解析失败"; + } + + _.each(sd.para.preset_properties, function(value, key) { + if (key.indexOf('latest_') === -1) { + return false; + } + key = key.slice(7); + if (value) { + if (key !== 'utm' && url_domain === "url解析失败") { + latestObj['$latest_' + key] = 'url的domain解析失败'; + } else if (_.isReferralTraffic(document.referrer)) { + switch (key) { + case 'traffic_source_type': + latestObj['$latest_traffic_source_type'] = _.getSourceFromReferrer(); + break; + case 'referrer': + latestObj['$latest_referrer'] = _.info.pageProp.referrer; + break; + case 'search_keyword': + latestObj['$latest_search_keyword'] = _.getKeywordFromReferrer(); + break; + case 'landing_page': + latestObj['$latest_landing_page'] = location.href; + break; + } + } + } else { + if (key === 'utm' && sd.store._state.props) { + for (var key1 in sd.store._state.props) { + if (key1.indexOf('$latest_utm') === 0 || key1.indexOf('_latest_') === 0) { + delete sd.store._state.props[key1]; + } + } + } else if (sd.store._state.props && (('$latest_' + key) in sd.store._state.props)) { + delete sd.store._state.props['$latest_' + key]; + } + } + }); + + sd.register(latestObj); + + if (sd.para.preset_properties.latest_utm) { + var allUtms = _.info.campaignParamsStandard('$latest_', '_latest_'); + var $utms = allUtms.$utms; + var otherUtms = allUtms.otherUtms; + if (!_.isEmptyObject($utms)) { + sd.register($utms); + } + if (!_.isEmptyObject(otherUtms)) { + sd.register(otherUtms); + } + } + + + } + + }; + + + + var heatmap = sd.heatmap = { + setNotice: function(web_url) { + sd.is_heatmap_render_mode = true; + + if (!sd.para.heatmap) { + sd.errorMsg = '您SDK没有配置开启点击图,可能没有数据!'; + } + if (web_url && web_url[0] && web_url[1]) { + if (web_url[1].slice(0, 5) === 'http:' && location.protocol === 'https:') { + sd.errorMsg = '您的当前页面是https的地址,神策分析环境也必须是https!'; + } + } + if (!sd.para.heatmap_url) { + sd.para.heatmap_url = location.protocol + '//static.sensorsdata.cn/sdk/' + sd.lib_version + '/heatmap.min.js'; + } + + }, + getDomIndex: function(el) { + if (!el.parentNode) return -1; + var i = 0; + var nodeName = el.tagName; + var list = el.parentNode.children; + for (var n = 0; n < list.length; n++) { + if (list[n].tagName === nodeName) { + if (el === list[n]) { + return i; + } else { + i++; + } + } + } + return -1; + }, + selector: function(el) { + var i = el.parentNode && 9 == el.parentNode.nodeType ? -1 : this.getDomIndex(el); + if (el.getAttribute && el.getAttribute('id') && (!sd.para.heatmap || (sd.para.heatmap && sd.para.heatmap.element_selector !== 'not_use_id'))) { + return '#' + el.getAttribute('id'); + } else { + return el.tagName.toLowerCase() + (~i ? ':nth-of-type(' + (i + 1) + ')' : ''); + } + }, + getDomSelector: function(el, arr) { + if (!el || !el.parentNode || !el.parentNode.children) { + return false; + } + arr = arr && arr.join ? arr : []; + var name = el.nodeName.toLowerCase(); + if (!el || name === 'body' || 1 != el.nodeType) { + arr.unshift('body'); + return arr.join(' > '); + } + arr.unshift(this.selector(el)); + if (el.getAttribute && el.getAttribute('id') && (sd.para.heatmap && sd.para.heatmap.element_selector !== 'not_use_id')) return arr.join(' > '); + return this.getDomSelector(el.parentNode, arr); + }, + na: function() { + var a = document.documentElement.scrollLeft || window.pageXOffset; + return parseInt(isNaN(a) ? 0 : a, 10); + }, + i: function() { + var a = 0; + try { + a = o.documentElement && o.documentElement.scrollTop || m.pageYOffset, + a = isNaN(a) ? 0 : a; + } catch (b) { + a = 0; + } + return parseInt(a, 10); + }, + getBrowserWidth: function() { + var a = window.innerWidth || document.body.clientWidth; + return isNaN(a) ? 0 : parseInt(a, 10); + }, + getBrowserHeight: function() { + var a = window.innerHeight || document.body.clientHeight; + return isNaN(a) ? 0 : parseInt(a, 10); + }, + getScrollWidth: function() { + var a = parseInt(document.body.scrollWidth, 10); + return isNaN(a) ? 0 : a; + }, + W: function(a) { + var b = parseInt(+a.clientX + +this.na(), 10); + var a = parseInt(+a.clientY + +this.i(), 10); + return { + x: isNaN(b) ? 0 : b, + y: isNaN(a) ? 0 : a + } + }, + start: function(ev, target, tagName, customProps, callback) { + var userCustomProps = _.isObject(customProps) ? customProps : {}; + var userCallback = _.isFunction(callback) ? callback : _.isFunction(customProps) ? customProps : undefined; + if (sd.para.heatmap && sd.para.heatmap.collect_element && !sd.para.heatmap.collect_element(target)) { + return false; + } + + var selector = this.getDomSelector(target); + var prop = _.getEleInfo({ + target: target + }); + + prop.$element_selector = selector ? selector : ''; + if (sd.para.heatmap && sd.para.heatmap.custom_property) { + var customP = sd.para.heatmap.custom_property(target); + if (_.isObject(customP)) { + prop = _.extend(prop, customP); + } + } + prop = _.extend(prop, userCustomProps); + if (tagName === 'a' && sd.para.heatmap && sd.para.heatmap.isTrackLink === true) { + _.trackLink({ + event: ev, + target: target + }, '$WebClick', prop); + } else { + sd.track('$WebClick', prop, userCallback); + } + + }, + hasElement: function(e) { + var path = e._getPath(); + if (_.isArray(path) && (path.length > 0)) { + for (var i = 0; i < path.length; i++) { + if (path[i] && path[i].tagName && (path[i].tagName.toLowerCase() === 'a')) { + return path[i]; + } + } + } + return false; + }, + + initScrollmap: function() { + if (!_.isObject(sd.para.heatmap) || sd.para.heatmap.scroll_notice_map !== 'default') { + return false; + } + + var checkPage = function() { + if (sd.para.scrollmap && _.isFunction(sd.para.scrollmap.collect_url) && !sd.para.scrollmap.collect_url()) { + return false; + } + return true; + }; + + var interDelay = function(param) { + var interDelay = {}; + interDelay.timeout = param.timeout || 1000; + interDelay.func = param.func; + interDelay.hasInit = false; + interDelay.inter = null; + interDelay.main = function(para, isClose) { + this.func(para, isClose); + this.inter = null; + }; + interDelay.go = function(isNoDelay) { + var me = this; + var para = {}; + if (!this.inter) { + para.$viewport_position = document.documentElement && document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop || 0; + para.$viewport_position = Math.round(para.$viewport_position) || 0; + para.$viewport_height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight || 0; + para.$viewport_width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth || 0; + if (isNoDelay) { + interDelay.main(para, true); + } else { + + this.inter = setTimeout(function() { + interDelay.main(para); + }, this.timeout); + + } + } + }; + return interDelay; + }; + + + var delayTime = interDelay({ + timeout: 1000, + func: function(para, isClose) { + var offsetTop = document.documentElement && document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop || 0; + var current_time = new Date(); + var delay_time = current_time - this.current_time; + if ((delay_time > sd.para.heatmap.scroll_delay_time && offsetTop - para.$viewport_position !== 0) || isClose) { + para.$url = location.href; + para.$title = document.title; + para.$url_path = location.pathname; + para.event_duration = Math.min(sd.para.heatmap.scroll_event_duration, parseInt(delay_time) / 1000); + sd.track('$WebStay', para); + } + this.current_time = current_time; + } + }); + + delayTime.current_time = new Date(); + + + _.addEvent(window, 'scroll', function() { + if (!checkPage()) { + return false; + } + delayTime.go(); + }); + + _.addEvent(window, 'unload', function() { + if (!checkPage()) { + return false; + } + delayTime.go('notime'); + }); + + + }, + initHeatmap: function() { + var that = this; + if (!_.isObject(sd.para.heatmap) || sd.para.heatmap.clickmap !== 'default') { + return false; + } + + if (_.isFunction(sd.para.heatmap.collect_url) && !sd.para.heatmap.collect_url()) { + return false; + } + + if (sd.para.heatmap.collect_elements === 'all') { + sd.para.heatmap.collect_elements = 'all'; + } else { + sd.para.heatmap.collect_elements = 'interact'; + } + + if (sd.para.heatmap.collect_elements === 'all') { + _.addEvent(document, 'click', function(e) { + var ev = e || window.event; + if (!ev) { + return false; + } + var target = ev.target || ev.srcElement; + if (typeof target !== 'object') { + return false; + } + if (typeof target.tagName !== 'string') { + return false; + } + var tagName = target.tagName.toLowerCase(); + if (tagName === 'body' || tagName === 'html') { + return false; + } + if (!target || !target.parentNode || !target.parentNode.children) { + return false; + } + var parent_ele = target.parentNode.tagName.toLowerCase(); + if (parent_ele === 'a' || parent_ele === 'button') { + that.start(ev, target.parentNode, parent_ele); + } else { + that.start(ev, target, tagName); + } + }); + + } else { + _.addEvent(document, 'click', function(e) { + var ev = e || window.event; + if (!ev) { + return false; + } + var target = ev.target || ev.srcElement; + if (typeof target !== 'object') { + return false; + } + if (typeof target.tagName !== 'string') { + return false; + } + var tagName = target.tagName.toLowerCase(); + if (tagName.toLowerCase() === 'body' || tagName.toLowerCase() === 'html') { + return false; + } + if (!target || !target.parentNode || !target.parentNode.children) { + return false; + } + + var parent_ele = target.parentNode; + + if (tagName === 'a' || tagName === 'button' || tagName === 'input' || tagName === 'textarea' || _.hasAttribute(target, 'data-sensors-click')) { + that.start(ev, target, tagName); + } else if (parent_ele.tagName.toLowerCase() === 'button' || parent_ele.tagName.toLowerCase() === 'a') { + that.start(ev, parent_ele, target.parentNode.tagName.toLowerCase()); + } else if (tagName === 'area' && parent_ele.tagName.toLowerCase() === 'map' && _.ry(parent_ele).prev().tagName && _.ry(parent_ele).prev().tagName.toLowerCase() === 'img') { + that.start(ev, _.ry(parent_ele).prev(), _.ry(parent_ele).prev().tagName.toLowerCase()); + } else { + var hasA = that.hasElement(e); + if (hasA) { + that.start(ev, hasA, hasA.tagName.toLowerCase()); + } + } + }); + } + + }, + initDefineMode : function(){ + function getAndPostDebugInfo(){ + var arr = []; + if(!((window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.sensorsdataNativeTracker && _.isObject(window.SensorsData_iOS_JS_Bridge) && window.SensorsData_iOS_JS_Bridge.sensorsdata_app_server_url) + ||(_.isObject(window.SensorsData_APP_New_H5_Bridge) && window.SensorsData_APP_New_H5_Bridge.sensorsdata_get_server_url && window.SensorsData_APP_New_H5_Bridge.sensorsdata_track))){ + arr.push(sd.debug.defineMode('1')); + } + if(!(_.isObject(sd.para.app_js_bridge))){ + arr.push(sd.debug.defineMode('2')); + } + if(!(_.isObject(sd.para.heatmap) && sd.para.heatmap.clickmap == 'default')){ + arr.push(sd.debug.defineMode('3')); + } + if(_.isObject(sd.para.app_js_bridge) && sd.para.app_js_bridge.defineModeDebugInfo == '4'){ + arr.push(sd.debug.defineMode('4')); + } + var data = { + callType: 'app_alert', + data: arr + } + + if(SensorsData_App_Visual_Bridge && SensorsData_App_Visual_Bridge.sensorsdata_visualized_alert_info){ + SensorsData_App_Visual_Bridge.sensorsdata_visualized_alert_info(JSON.stringify(data)); + }else if(window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.sensorsdataNativeTracker && window.webkit.messageHandlers.sensorsdataNativeTracker.postMessage){ + window.webkit.messageHandlers.sensorsdataNativeTracker.postMessage(JSON.stringify(data)); + } + + } + if(_.isObject(window.SensorsData_App_Visual_Bridge) && window.SensorsData_App_Visual_Bridge.sensorsdata_visualized_mode && ((window.SensorsData_App_Visual_Bridge.sensorsdata_visualized_mode === true) || (window.SensorsData_App_Visual_Bridge.sensorsdata_visualized_mode()))){ + if(_.isObject(sd.para.heatmap) && sd.para.heatmap.clickmap == 'default'){ + if(_.isObject(sd.para.app_js_bridge) && sd.para.app_js_bridge.H5verify){ + _.loadScript({ + success:function(){ + setTimeout(function(){ + if(typeof sa_jssdk_app_define_mode !== 'undefined'){ + sa_jssdk_app_define_mode(sd); + } + },0); + }, + error:function(){}, + type:'js', + url: './vapph5define.js' + }); + }else{ + //打通失败弹框debug信息传给App + getAndPostDebugInfo(); + } + }else{ + //未开启全埋点弹框 + getAndPostDebugInfo(); + } + + + } + + }, + prepare: function(todo) { + var match = location.search.match(/sa-request-id=([^&#]+)/); + var type = location.search.match(/sa-request-type=([^&#]+)/); + var web_url = location.search.match(/sa-request-url=([^&#]+)/); + + var me = this; + + function isReady(data, type, url) { + if (sd.para.heatmap_url) { + _.loadScript({ + success: function() { + setTimeout(function() { + if (typeof sa_jssdk_heatmap_render !== 'undefined') { + sa_jssdk_heatmap_render(sd, data, type, url); + if (typeof console === 'object' && typeof console.log === 'function') { + if (!(sd.heatmap_version && (sd.heatmap_version === sd.lib_version))) { + console.log('heatmap.js与sensorsdata.js版本号不一致,可能存在风险!'); + } + } + } + }, 0); + }, + error: function() {}, + type: 'js', + url: sd.para.heatmap_url + }); + } else { + sd.log('没有指定heatmap_url的路径'); + } + + } + if (match && match[0] && match[1]) { + heatmap.setNotice(web_url); + if (_.sessionStorage.isSupport()) { + if (web_url && web_url[0] && web_url[1]) { + sessionStorage.setItem('sensors_heatmap_url', decodeURIComponent(web_url[1])); + } + sessionStorage.setItem('sensors_heatmap_id', match[1]); + + if (type && type[0] && type[1]) { + if (type[1] === '1' || type[1] === '2' || type[1] === '3') { + type = type[1]; + sessionStorage.setItem('sensors_heatmap_type', type); + } else { + type = null; + } + } else { + if (sessionStorage.getItem('sensors_heatmap_type') !== null) { + type = sessionStorage.getItem('sensors_heatmap_type'); + } else { + type = null; + } + } + } + isReady(match[1], type); + } else if (_.sessionStorage.isSupport() && typeof sessionStorage.getItem('sensors_heatmap_id') === 'string') { + heatmap.setNotice(); + isReady(sessionStorage.getItem('sensors_heatmap_id'), sessionStorage.getItem('sensors_heatmap_type'), location.href); + } else { + me.initDefineMode(); + todo(); + if (_.isObject(sd.para.heatmap)) { + this.initHeatmap(); + this.initScrollmap(); + } + } + + + + } + }; + + + + + sd.init = function(para) { + if (sd.readyState && sd.readyState.state && sd.readyState.state >= 2) { + return false; + } + sd.setInitVar(); + sd.readyState.setState(2); + sd.initPara(para); + + function app_js_bridge() { + var app_info = null; + var todo = null; + + function setAppInfo(data) { + app_info = data; + if (_.isJSONString(app_info)) { + app_info = JSON.parse(app_info); + } + if (todo) { + todo(app_info); + todo = null; + app_info = null; + } + } + + function getAndroid() { + if (typeof window.SensorsData_APP_JS_Bridge === 'object' && window.SensorsData_APP_JS_Bridge.sensorsdata_call_app) { + app_info = SensorsData_APP_JS_Bridge.sensorsdata_call_app(); + if (_.isJSONString(app_info)) { + app_info = JSON.parse(app_info); + } + } + } + window.sensorsdata_app_js_bridge_call_js = function(data) { + setAppInfo(data); + }; + + function calliOS() { + if (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) { + var iframe = document.createElement("iframe"); + iframe.setAttribute("src", "sensorsanalytics://getAppInfo"); + document.documentElement.appendChild(iframe); + iframe.parentNode.removeChild(iframe); + iframe = null; + } + } + sd.getAppStatus = function(func) { + calliOS(); + getAndroid(); + if (!func) { + return app_info; + app_info = null; + } else { + if (app_info === null) { + todo = func; + } else { + func(app_info); + app_info = null; + } + } + }; + } + + heatmap.prepare(function() { + app_js_bridge(); + _.info.initPage(); + + if (sd.para.is_track_single_page) { + _.addSinglePageEvent(function(last_url) { + var sendData = function(extraData) { + extraData = extraData || {}; + if (last_url !== location.href) { + _.info.pageProp.referrer = last_url; + sd.quick("autoTrack", _.extend({ + $url: location.href, + $referrer: last_url + }, extraData)); + } + }; + if (typeof sd.para.is_track_single_page === "boolean") { + sendData(); + } else if (typeof sd.para.is_track_single_page === "function") { + var returnValue = sd.para.is_track_single_page(); + if (_.isObject(returnValue)) { + sendData(returnValue); + } else if (returnValue === true) { + sendData(); + } + } + }); + } + if (sd.para.batch_send) { + sd.batchSend.batchInterval(); + } + sd.store.init(); + + sd.readyState.setState(3); + if (sd._q && _.isArray(sd._q) && sd._q.length > 0) { + _.each(sd._q, function(content) { + sd[content[0]].apply(sd, Array.prototype.slice.call(content[1])); + }); + } + + }); + + }; + + var methods = ['track', 'quick', 'register', 'registerPage', 'registerOnce', 'trackSignup', 'setProfile', 'setOnceProfile', 'appendProfile', 'incrementProfile', 'deleteProfile', 'unsetProfile', 'identify', 'login', 'logout', 'trackLink', 'clearAllRegister']; + + _.each(methods, function(method) { + var oldFunc = sd[method]; + sd[method] = function() { + if (!sd.readyState.getState()) { + try { + console.error('请先初始化神策JS SDK'); + } catch (e) { + sd.log(e); + } + return; + } + return oldFunc.apply(sd, arguments); + }; + }); + + + + if (typeof window['sensorsDataAnalytic201505'] === 'string') { + sd.setPreConfig(window[sensorsDataAnalytic201505]); + window[sensorsDataAnalytic201505] = sd; + window['sensorsDataAnalytic201505'] = sd; + sd.init(); + } else if (typeof window['sensorsDataAnalytic201505'] === 'undefined') { + window['sensorsDataAnalytic201505'] = sd; + return sd; + } else { + return window['sensorsDataAnalytic201505']; + } + + + + + } catch (err) { + if (typeof console === 'object' && console.log) { + try { + console.log(err) + } catch (e) { + sd.log(e); + + }; + } + } + + + +}); \ No newline at end of file diff --git a/demo/src/main/assets/visual_h5_test/vapph5define.js b/demo/src/main/assets/visual_h5_test/vapph5define.js new file mode 100755 index 0000000..c0bb001 --- /dev/null +++ b/demo/src/main/assets/visual_h5_test/vapph5define.js @@ -0,0 +1,223 @@ + + +;(function(){ + var defineStore = { + sdStore : null, + getDefineTags : function (child){ + var arr = []; + var DefineTagNum = 0; + + function targetHandle(target,index){ + var tagstore = { + level : index, + id : 'h' + DefineTagNum + }; + DefineTagNum ++; + target.sensorsDefineStore = tagstore; + arr.push(target); + } + //递归便利获取所有可圈选元素的信息 obj + function func(obj,index){ + for(var i=0;i -1){ + targetHandle(target,index); + }else if (parent_ele && (parent_ele_tagName === 'button' || parent_ele_tagName === 'a')) { + targetHandle(parent_ele,index); + }else if(grand_ele && (grand_ele_tagName === 'button' || grand_ele_tagName === 'a')){ + targetHandle(grand_ele,index); + } + + +        if(target.children){ + func(target.children,index+1); +       } +      } + } + func(child,1); + return arr; + + }, + getVisibility : function(el){ + return (_isVisible(el)); + function _isVisible(el) { + var p = el.parentNode; + + if ( 9 === p.nodeType ) { + return true; + } + if ( + '0' === _getStyle(el, 'opacity') || + 'none' === _getStyle(el, 'display') || + 'hidden' === _getStyle(el, 'visibility') + ) { + return false; + } + var po = el.getBoundingClientRect(); + if ( p ) { + if ( ('hidden' === _getStyle(p, 'overflow') || 'scroll' === _getStyle(p, 'overflow')) ) { + var parentPo = p.getBoundingClientRect(); + if ( + (po.bottom <= parentPo.top)|| + (po.top >= parentPo.bottom)|| + (po.right <= parentPo.left)|| + (po.left >= parentPo.right) + ) { + return false; + } + } + return _isVisible(p); + } + return true; + } + + function _getStyle(el, property) { + if ( window.getComputedStyle ) { + return document.defaultView.getComputedStyle(el,null)[property]; + } + if ( el.currentStyle ) { + return el.currentStyle[property]; + } + } + + + }, + //zIndex 取值为 level+zIndex + getZIndex : function(el){ + var zIndex = window.getComputedStyle(el,null).getPropertyValue("z-index"); + var indexNum = 0; + if(zIndex && !isNaN(+zIndex)){ + indexNum = +zIndex; + } + if(this.sdStore._.isObject(el.sensorsDefineStore)){ + indexNum += el.sensorsDefineStore.level; + } + return indexNum; + }, + //获取可圈选子元素 + getSubElements : function(el){ + var elementsArr = []; + function testTag(el){ + if(el.children){ + for(var i=0;i { + int a = 10; + }); + } + + void test2(View view){ + view.setOnClickListener(view1 -> { + int a = 20; + }); + } +} diff --git a/demo/src/main/java/com/sensorsdata/analytics/android/demo/H5Activity.kt b/demo/src/main/java/com/sensorsdata/analytics/android/demo/H5Activity.kt new file mode 100644 index 0000000..65afba2 --- /dev/null +++ b/demo/src/main/java/com/sensorsdata/analytics/android/demo/H5Activity.kt @@ -0,0 +1,78 @@ +package com.sensorsdata.analytics.android.demo + +import android.os.Bundle +import android.webkit.JavascriptInterface +import android.webkit.WebView +import com.sensorsdata.analytics.android.sdk.SALog +import org.json.JSONObject + +class H5Activity : BaseActivity() { + private val TAG: String = "H5Activity" + private lateinit var androidWebView:AAWebView + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_h5) + //x5WebView.addJavascriptInterface(JsObject(), "sensorsDataObj") +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { +// webView.settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW +// } + //SensorsDataAPI.sharedInstance().showUpX5WebView(x5WebView, true) + + + //SensorsDataAPI.sharedInstance().showUpWebView(androidWebView, true,true) + //androidWebView.loadUrl("https://869359954.github.io/App_H5_traffic_sdk/index.html") + //本地新版 H5 + androidWebView = findViewById(R.id.androidWebView) + androidWebView.loadUrl("file:///android_asset/new_h5_test/index.html") + //旧版 H5 + //androidWebView.loadUrl("https://fengandyun.github.io/apph5select/index.html") + + //SensorsDataAPI.sharedInstance().showUpWebView(androidWebView, true, true) + + } + + private fun webview() { + run { + val webView = AWebView(this) + val testUrl1 = "hhh" + webView.loadUrl(testUrl1 + "uiuiuiuiuiuiui") + webView.loadData("data1", "html", "utf8") + webView.loadUrl("https://www.ss.cn", mapOf("header" to "h1")) + webView.loadDataWithBaseURL("http://www.base.cn", "h1=5", "text", "utf8", "http://www.hisotory.cn") + webView.postUrl("sss" , byteArrayOf()) + } + + run { + val aaWebView = AAWebView(this) + val testUrl1 = "hhh" + aaWebView.loadUrl(testUrl1 + "uiuiuiuiuiuiui") + aaWebView.loadData("data1", "html", "utf8") + aaWebView.loadUrl("https://www.ss.cn", mapOf("header" to "h1")) + aaWebView.loadDataWithBaseURL("http://www.base.cn", "h1=5", "text", "utf8", "http://www.hisotory.cn") + } + + } + + private class JsObject { + @JavascriptInterface + fun track(obj: JSONObject) { + SALog.i("JsObject", "from h5: $obj") + } + } + + private fun testWeb() { + val webView = WebView(this) + webView.loadUrl("http://www.baidu.com") + } + + private fun testWeb2() { + val webView = AWebView(this) + webView.loadUrl("http://www.baidu.com") + } + + private fun testWeb3() { + val webView = AAWebView(this) + webView.loadUrl("http://www.baidu.com") + } +} \ No newline at end of file diff --git a/demo/src/main/java/com/sensorsdata/analytics/android/demo/MainActivity.kt b/demo/src/main/java/com/sensorsdata/analytics/android/demo/MainActivity.kt new file mode 100644 index 0000000..dca1404 --- /dev/null +++ b/demo/src/main/java/com/sensorsdata/analytics/android/demo/MainActivity.kt @@ -0,0 +1,48 @@ +package com.sensorsdata.analytics.android.demo + +import android.app.PendingIntent +import android.content.Intent +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.view.KeyEvent +import android.view.MotionEvent +import android.webkit.WebView +import android.widget.Button +import androidx.core.app.NotificationCompat +import androidx.core.app.NotificationManagerCompat + +class MainActivity : AppCompatActivity() { + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + findViewById