1.android 代码不更新
react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res
2.iphone 12 底部适配问题
https://www.jianshu.com/p/e1da502fac49
- "react-native-share": "1.2.1",
崩溃问题
UIViewController *controller = RCTPresentedViewController();
shareController.completionWithItemsHandler = ^(NSString *activityType, BOOL completed, __unused NSArray *returnedItems, NSError *activityError) {
if (activityError) {
failureCallback(activityError);
} else if (completed){
successCallback(@[@(completed), RCTNullIfNil(activityType)]);
}
};
分享Telegram app 分享失败
RCTActionSheetManager.m // 145行
// [items addObject:data];
UIImage *image = [UIImage imageWithData: data];
if(image) {
[items addObject:image];
}
android中 TargetChosenReceiver.java 56行
Intent intent = new Intent(sTargetChosenReceiveAction);
intent.setPackage(reactContext.getPackageName());
intent.putExtra(EXTRA_RECEIVER_TOKEN, sLastRegisteredReceiver.hashCode());
final PendingIntent callback = PendingIntent.getBroadcast(reactContext, 0, intent,
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ?
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE :
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
// final PendingIntent callback = PendingIntent.getBroadcast(reactContext, 0, intent,
// PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
4.ios OPPOSans 字体修复
RCTFont.mm 335行修改
if (![familyName isEqualToString:@"OPPOSans"]) {
// Get the closest font that matches the given weight for the fontFamily
CGFloat closestWeight = INFINITY;
for (NSString *name in [UIFont fontNamesForFamilyName:familyName]) {
UIFont *match = [UIFont fontWithName:name size:fontSize];
if (isItalic == isItalicFont(match) &&
isCondensed == isCondensedFont(match)) {
CGFloat testWeight = weightOfFont(match);
if (ABS(testWeight - fontWeight) < ABS(closestWeight - fontWeight)) {
font = match;
closestWeight = testWeight;
}
}
}
}
5.android 编译需要 升级到 支持androidX
6.ios 运行
(一)
替换 parseIOSDevicesList.js runIOS.js
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* strict
*/
/**
* Parses the output of `xcrun simctl list devices` command
*/
function parseIOSDevicesList(text) {
const devices = [];
text.stdout.split('\n').forEach(line => {
const device = line.match(
/(.*?) (\(([0-9.]+)\) )?\(([0-9A-F-]+)\)( \(Simulator\))?/i,
)
if (device) {
const [, name,, version, udid, isSimulator] = device;
const metadata = {
name,
udid
};
if (version) {
metadata.version = version;
metadata.type = isSimulator ? 'simulator' : 'device';
} else {
metadata.type = 'catalyst';
}
devices.push(metadata);
}
});
return devices;
}
var _default = parseIOSDevicesList;
exports.default = _default;
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
function _child_process() {
const data = _interopRequireDefault(require("child_process"));
_child_process = function () {
return data;
};
return data;
}
function _execa() {
const data = _interopRequireDefault(require("execa"));
_execa = function () {
return data;
};
return data;
}
function _fs() {
const data = _interopRequireDefault(require("fs"));
_fs = function () {
return data;
};
return data;
}
function _path() {
const data = _interopRequireDefault(require("path"));
_path = function () {
return data;
};
return data;
}
var _findXcodeProject = _interopRequireDefault(require("./findXcodeProject"));
var _parseIOSDevicesList = _interopRequireDefault(require("./parseIOSDevicesList"));
var _findMatchingSimulator = _interopRequireDefault(require("./findMatchingSimulator"));
var _errors = require("../../tools/errors");
var _logger = _interopRequireDefault(require("../../tools/logger"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function runIOS(_, ctx, args) {
if (!_fs().default.existsSync(args.projectPath)) {
throw new Error('iOS project folder not found. Are you sure this is a React Native project?');
}
process.chdir(args.projectPath);
const xcodeProject = (0, _findXcodeProject.default)(_fs().default.readdirSync('.'));
if (!xcodeProject) {
throw new Error(`Could not find Xcode project files in "${args.projectPath}" folder`);
}
const inferredSchemeName = _path().default.basename(xcodeProject.name, _path().default.extname(xcodeProject.name));
const scheme = args.scheme || inferredSchemeName;
_logger.default.info(`Found Xcode ${xcodeProject.isWorkspace ? 'workspace' : 'project'} ${xcodeProject.name}`);
// const devices = (0, _parseIOSDevicesList.default)( // $FlowExpectedError https://github.com/facebook/flow/issues/5675
// _child_process().default.execFileSync('xcrun', ['instruments', '-s'], {
// encoding: 'utf8'
// }));
const devices = (0, _parseIOSDevicesList.default)(_execa().default.sync('xcrun', ['xctrace', 'list', 'devices']));
if (args.device) {
const selectedDevice = matchingDevice(devices, args.device);
if (selectedDevice) {
return runOnDevice(selectedDevice, scheme, xcodeProject, args.configuration, args.packager, args.verbose, args.port);
}
if (devices && devices.length > 0) {
// $FlowIssue: args.device is defined in this context
_logger.default.error(`Could not find device with the name: "${args.device}".
Choose one of the following:${printFoundDevices(devices)}`);
} else {
_logger.default.error('No iOS devices connected.');
}
} else if (args.udid) {
// $FlowIssue: args.udid is defined in this context
return runOnDeviceByUdid(args, scheme, xcodeProject, devices);
}
return runOnSimulator(xcodeProject, args, scheme);
}
function runOnDeviceByUdid(args, scheme, xcodeProject, devices) {
const selectedDevice = matchingDeviceByUdid(devices, args.udid);
if (selectedDevice) {
runOnDevice(selectedDevice, scheme, xcodeProject, args.configuration, args.packager, args.verbose, args.port);
return;
}
if (devices && devices.length > 0) {
// $FlowIssue: args.udid is defined in this context
_logger.default.error(`Could not find device with the udid: "${args.udid}".
Choose one of the following:\n${printFoundDevices(devices)}`);
} else {
_logger.default.error('No iOS devices connected.');
}
}
async function runOnSimulator(xcodeProject, args, scheme) {
let simulators;
try {
simulators = JSON.parse( // $FlowIssue: https://github.com/facebook/flow/issues/5675
_child_process().default.execFileSync('xcrun', ['simctl', 'list', '--json', 'devices'], {
encoding: 'utf8'
}));
} catch (e) {
throw new Error('Could not parse the simulator list output');
}
const selectedSimulator = (0, _findMatchingSimulator.default)(simulators, args.simulator);
if (!selectedSimulator) {
throw new Error(`Could not find ${args.simulator} simulator`);
}
/**
* Booting simulator through `xcrun simctl boot` will boot it in the `headless` mode
* (running in the background).
*
* In order for user to see the app and the simulator itself, we have to make sure
* that the Simulator.app is running.
*
* We also pass it `-CurrentDeviceUDID` so that when we launch it for the first time,
* it will not boot the "default" device, but the one we set. If the app is already running,
* this flag has no effect.
*/
const activeDeveloperDir = _child_process().default.execFileSync('xcode-select', ['-p'], {
encoding: 'utf8'
}) // $FlowExpectedError https://github.com/facebook/flow/issues/5675
.trim();
_child_process().default.execFileSync('open', [`${activeDeveloperDir}/Applications/Simulator.app`, '--args', '-CurrentDeviceUDID', selectedSimulator.udid]);
if (!selectedSimulator.booted) {
bootSimulator(selectedSimulator);
}
const appName = await buildProject(xcodeProject, selectedSimulator.udid, scheme, args.configuration, args.packager, args.verbose, args.port);
const appPath = getBuildPath(args.configuration, appName, false, scheme);
_logger.default.info(`Installing ${appPath}`);
_child_process().default.spawnSync('xcrun', ['simctl', 'install', selectedSimulator.udid, appPath], {
stdio: 'inherit'
});
const bundleID = _child_process().default.execFileSync('/usr/libexec/PlistBuddy', ['-c', 'Print:CFBundleIdentifier', _path().default.join(appPath, 'Info.plist')], {
encoding: 'utf8'
}) // $FlowExpectedError https://github.com/facebook/flow/issues/5675
.trim();
_logger.default.info(`Launching ${bundleID}`);
_child_process().default.spawnSync('xcrun', ['simctl', 'launch', selectedSimulator.udid, bundleID], {
stdio: 'inherit'
});
}
async function runOnDevice(selectedDevice, scheme, xcodeProject, configuration, launchPackager, verbose, port) {
const appName = await buildProject(xcodeProject, selectedDevice.udid, scheme, configuration, launchPackager, verbose, port);
const iosDeployInstallArgs = ['--bundle', getBuildPath(configuration, appName, true, scheme), '--id', selectedDevice.udid, '--justlaunch'];
_logger.default.info(`installing and launching your app on ${selectedDevice.name}...`);
const iosDeployOutput = _child_process().default.spawnSync('ios-deploy', iosDeployInstallArgs, {
encoding: 'utf8'
});
if (iosDeployOutput.error) {
_logger.default.error('** INSTALLATION FAILED **\nMake sure you have ios-deploy installed globally.\n(e.g "npm install -g ios-deploy")');
} else {
_logger.default.info('** INSTALLATION SUCCEEDED **');
}
}
function buildProject(xcodeProject, udid, scheme, configuration, launchPackager = false, verbose, port) {
return new Promise((resolve, reject) => {
const xcodebuildArgs = [xcodeProject.isWorkspace ? '-workspace' : '-project', xcodeProject.name, '-configuration', configuration, '-scheme', scheme, '-destination', `id=${udid}`, '-derivedDataPath', `build/${scheme}`];
_logger.default.info(`Building using "xcodebuild ${xcodebuildArgs.join(' ')}"`);
let xcpretty;
if (!verbose) {
xcpretty = xcprettyAvailable() && _child_process().default.spawn('xcpretty', [], {
stdio: ['pipe', process.stdout, process.stderr]
});
}
const buildProcess = _child_process().default.spawn('xcodebuild', xcodebuildArgs, getProcessOptions(launchPackager, port));
let buildOutput = '';
let errorOutput = '';
buildProcess.stdout.on('data', data => {
buildOutput += data.toString();
if (xcpretty) {
xcpretty.stdin.write(data);
} else {
_logger.default.info(data.toString());
}
});
buildProcess.stderr.on('data', data => {
errorOutput += data;
});
buildProcess.on('close', code => {
if (xcpretty) {
xcpretty.stdin.end();
}
if (code !== 0) {
reject(new _errors.ProcessError(['Failed to build iOS project.', `We ran "xcodebuild" command but it exited with error code ${code}.`, `To debug build logs further, consider building your app with Xcode.app, by opening ${xcodeProject.name}`].join(' '), errorOutput));
return;
}
resolve(getProductName(buildOutput) || scheme);
});
});
}
function bootSimulator(selectedSimulator) {
const simulatorFullName = formattedDeviceName(selectedSimulator);
_logger.default.info(`Launching ${simulatorFullName}...`);
try {
_child_process().default.spawnSync('xcrun', ['instruments', '-w', selectedSimulator.udid]);
} catch (_ignored) {// instruments always fail with 255 because it expects more arguments,
// but we want it to only launch the simulator
}
}
function getBuildPath(configuration, appName, isDevice, scheme) {
let device;
if (isDevice) {
device = 'iphoneos';
} else if (appName.toLowerCase().includes('tvos')) {
device = 'appletvsimulator';
} else {
device = 'iphonesimulator';
}
let buildPath = `build/${scheme}/Build/Products/${configuration}-${device}/${appName}.app`; // Check wether app file exist, sometimes `-derivedDataPath` option of `xcodebuild` not works as expected.
if (!_fs().default.existsSync(_path().default.join(buildPath))) {
return `DerivedData/Build/Products/${configuration}-${device}/${appName}.app`;
}
return buildPath;
}
function getProductName(buildOutput) {
const productNameMatch = /export FULL_PRODUCT_NAME="?(.+).app"?$/m.exec(buildOutput);
return productNameMatch ? productNameMatch[1] : null;
}
function xcprettyAvailable() {
try {
_child_process().default.execSync('xcpretty --version', {
stdio: [0, 'pipe', 'ignore']
});
} catch (error) {
return false;
}
return true;
}
function matchingDevice(devices, deviceName) {
if (deviceName === true && devices.length === 1) {
_logger.default.info(`Using first available device ${devices[0].name} due to lack of name supplied.`);
return devices[0];
}
for (let i = devices.length - 1; i >= 0; i--) {
if (devices[i].name === deviceName || formattedDeviceName(devices[i]) === deviceName) {
return devices[i];
}
}
return null;
}
function matchingDeviceByUdid(devices, udid) {
for (let i = devices.length - 1; i >= 0; i--) {
if (devices[i].udid === udid) {
return devices[i];
}
}
return null;
}
function formattedDeviceName(simulator) {
return `${simulator.name} (${simulator.version})`;
}
function printFoundDevices(devices) {
let output = '';
for (let i = devices.length - 1; i >= 0; i--) {
output += `${devices[i].name} Udid: ${devices[i].udid}\n`;
}
return output;
}
function getProcessOptions(launchPackager, port) {
if (launchPackager) {
return {
env: _objectSpread({}, process.env, {
RCT_METRO_PORT: port
})
};
}
return {
env: _objectSpread({}, process.env, {
RCT_NO_LAUNCH_PACKAGER: true
})
};
}
var _default = {
name: 'run-ios',
description: 'builds your app and starts it on iOS simulator',
func: runIOS,
examples: [{
desc: 'Run on a different simulator, e.g. iPhone 5',
cmd: 'react-native run-ios --simulator "iPhone 5"'
}, {
desc: 'Pass a non-standard location of iOS directory',
cmd: 'react-native run-ios --project-path "./app/ios"'
}, {
desc: "Run on a connected device, e.g. Max's iPhone",
cmd: 'react-native run-ios --device "Max\'s iPhone"'
}, {
desc: 'Run on the AppleTV simulator',
cmd: 'react-native run-ios --simulator "Apple TV" --scheme "helloworld-tvOS"'
}],
options: [{
command: '--simulator [string]',
description: 'Explicitly set simulator to use. Optionally include iOS version between' + 'parenthesis at the end to match an exact version: "iPhone 6 (10.0)"',
default: 'iPhone X'
}, {
command: '--configuration [string]',
description: 'Explicitly set the scheme configuration to use',
default: 'Debug'
}, {
command: '--scheme [string]',
description: 'Explicitly set Xcode scheme to use'
}, {
command: '--project-path [string]',
description: 'Path relative to project root where the Xcode project ' + '(.xcodeproj) lives.',
default: 'ios'
}, {
command: '--device [string]',
description: 'Explicitly set device to use by name. The value is not required if you have a single device connected.'
}, {
command: '--udid [string]',
description: 'Explicitly set device to use by udid'
}, {
command: '--no-packager',
description: 'Do not launch packager while building'
}, {
command: '--verbose',
description: 'Do not use xcpretty even if installed'
}, {
command: '--port [number]',
default: process.env.RCT_METRO_PORT || 8081,
parse: val => Number(val)
}]
};
exports.default = _default;
(二)
替换
fishhook.c
// Copyright (c) 2013, Facebook, Inc.
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name Facebook nor the names of its contributors may be used to
// endorse or promote products derived from this software without specific
// prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "fishhook.h"
#include <dlfcn.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <mach/mach.h>
#include <mach/vm_map.h>
#include <mach/vm_region.h>
#include <mach-o/dyld.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#ifdef __LP64__
typedef struct mach_header_64 mach_header_t;
typedef struct segment_command_64 segment_command_t;
typedef struct section_64 section_t;
typedef struct nlist_64 nlist_t;
#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64
#else
typedef struct mach_header mach_header_t;
typedef struct segment_command segment_command_t;
typedef struct section section_t;
typedef struct nlist nlist_t;
#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT
#endif
#ifndef SEG_DATA_CONST
#define SEG_DATA_CONST "__DATA_CONST"
#endif
struct rebindings_entry {
struct rebinding *rebindings;
size_t rebindings_nel;
struct rebindings_entry *next;
};
static struct rebindings_entry *_rebindings_head;
static int prepend_rebindings(struct rebindings_entry **rebindings_head,
struct rebinding rebindings[],
size_t nel) {
struct rebindings_entry *new_entry = (struct rebindings_entry *) malloc(sizeof(struct rebindings_entry));
if (!new_entry) {
return -1;
}
new_entry->rebindings = (struct rebinding *) malloc(sizeof(struct rebinding) * nel);
if (!new_entry->rebindings) {
free(new_entry);
return -1;
}
memcpy(new_entry->rebindings, rebindings, sizeof(struct rebinding) * nel);
new_entry->rebindings_nel = nel;
new_entry->next = *rebindings_head;
*rebindings_head = new_entry;
return 0;
}
#if 0
static int get_protection(void *addr, vm_prot_t *prot, vm_prot_t *max_prot) {
mach_port_t task = mach_task_self();
vm_size_t size = 0;
vm_address_t address = (vm_address_t)addr;
memory_object_name_t object;
#ifdef __LP64__
mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
vm_region_basic_info_data_64_t info;
kern_return_t info_ret = vm_region_64(
task, &address, &size, VM_REGION_BASIC_INFO_64, (vm_region_info_64_t)&info, &count, &object);
#else
mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT;
vm_region_basic_info_data_t info;
kern_return_t info_ret = vm_region(task, &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)&info, &count, &object);
#endif
if (info_ret == KERN_SUCCESS) {
if (prot != NULL)
*prot = info.protection;
if (max_prot != NULL)
*max_prot = info.max_protection;
return 0;
}
return -1;
}
#endif
static void perform_rebinding_with_section(struct rebindings_entry *rebindings,
section_t *section,
intptr_t slide,
nlist_t *symtab,
char *strtab,
uint32_t *indirect_symtab) {
uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1;
void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr);
for (uint i = 0; i < section->size / sizeof(void *); i++) {
uint32_t symtab_index = indirect_symbol_indices[i];
if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL ||
symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) {
continue;
}
uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx;
char *symbol_name = strtab + strtab_offset;
bool symbol_name_longer_than_1 = symbol_name[0] && symbol_name[1];
struct rebindings_entry *cur = rebindings;
while (cur) {
for (uint j = 0; j < cur->rebindings_nel; j++) {
if (symbol_name_longer_than_1 && strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) {
kern_return_t err;
if (cur->rebindings[j].replaced != NULL && indirect_symbol_bindings[i] != cur->rebindings[j].replacement)
*(cur->rebindings[j].replaced) = indirect_symbol_bindings[i];
/**
* 1. Moved the vm protection modifying codes to here to reduce the
* changing scope.
* 2. Adding VM_PROT_WRITE mode unconditionally because vm_region
* API on some iOS/Mac reports mismatch vm protection attributes.
* -- Lianfu Hao Jun 16th, 2021
**/
err = vm_protect (mach_task_self (), (uintptr_t)indirect_symbol_bindings, section->size, 0, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY);
if (err == KERN_SUCCESS) {
/**
* Once we failed to change the vm protection, we
* MUST NOT continue the following write actions!
* iOS 15 has corrected the const segments prot.
* -- Lionfore Hao Jun 11th, 2021
**/
indirect_symbol_bindings[i] = cur->rebindings[j].replacement;
}
goto symbol_loop;
}
}
cur = cur->next;
}
symbol_loop:;
}
}
static void rebind_symbols_for_image(struct rebindings_entry *rebindings,
const struct mach_header *header,
intptr_t slide) {
Dl_info info;
if (dladdr(header, &info) == 0) {
return;
}
segment_command_t *cur_seg_cmd;
segment_command_t *linkedit_segment = NULL;
struct symtab_command* symtab_cmd = NULL;
struct dysymtab_command* dysymtab_cmd = NULL;
uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t);
for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) {
cur_seg_cmd = (segment_command_t *)cur;
if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) {
if (strcmp(cur_seg_cmd->segname, SEG_LINKEDIT) == 0) {
linkedit_segment = cur_seg_cmd;
}
} else if (cur_seg_cmd->cmd == LC_SYMTAB) {
symtab_cmd = (struct symtab_command*)cur_seg_cmd;
} else if (cur_seg_cmd->cmd == LC_DYSYMTAB) {
dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd;
}
}
if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment ||
!dysymtab_cmd->nindirectsyms) {
return;
}
// Find base symbol/string table addresses
uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff;
nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff);
char *strtab = (char *)(linkedit_base + symtab_cmd->stroff);
// Get indirect symbol table (array of uint32_t indices into symbol table)
uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff);
cur = (uintptr_t)header + sizeof(mach_header_t);
for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) {
cur_seg_cmd = (segment_command_t *)cur;
if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) {
if (strcmp(cur_seg_cmd->segname, SEG_DATA) != 0 &&
strcmp(cur_seg_cmd->segname, SEG_DATA_CONST) != 0) {
continue;
}
for (uint j = 0; j < cur_seg_cmd->nsects; j++) {
section_t *sect =
(section_t *)(cur + sizeof(segment_command_t)) + j;
if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) {
perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab);
}
if ((sect->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS) {
perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab);
}
}
}
}
}
static void _rebind_symbols_for_image(const struct mach_header *header,
intptr_t slide) {
rebind_symbols_for_image(_rebindings_head, header, slide);
}
int rebind_symbols_image(void *header,
intptr_t slide,
struct rebinding rebindings[],
size_t rebindings_nel) {
struct rebindings_entry *rebindings_head = NULL;
int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel);
rebind_symbols_for_image(rebindings_head, (const struct mach_header *) header, slide);
if (rebindings_head) {
free(rebindings_head->rebindings);
}
free(rebindings_head);
return retval;
}
int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) {
int retval = prepend_rebindings(&_rebindings_head, rebindings, rebindings_nel);
if (retval < 0) {
return retval;
}
// If this was the first call, register callback for image additions (which is also invoked for
// existing images, otherwise, just run on existing images
if (!_rebindings_head->next) {
_dyld_register_func_for_add_image(_rebind_symbols_for_image);
} else {
uint32_t c = _dyld_image_count();
for (uint32_t i = 0; i < c; i++) {
_rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i));
}
}
return retval;
}
fishhook.h
// Copyright (c) 2013, Facebook, Inc.
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name Facebook nor the names of its contributors may be used to
// endorse or promote products derived from this software without specific
// prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef fishhook_h
#define fishhook_h
#include <stddef.h>
#include <stdint.h>
#if !defined(FISHHOOK_EXPORT)
#define FISHHOOK_VISIBILITY __attribute__((visibility("hidden")))
#else
#define FISHHOOK_VISIBILITY __attribute__((visibility("default")))
#endif
#ifdef __cplusplus
extern "C" {
#endif //__cplusplus
/*
* A structure representing a particular intended rebinding from a symbol
* name to its replacement
*/
struct rebinding {
const char *name;
void *replacement;
void **replaced;
};
/*
* For each rebinding in rebindings, rebinds references to external, indirect
* symbols with the specified name to instead point at replacement for each
* image in the calling process as well as for all future images that are loaded
* by the process. If rebind_functions is called more than once, the symbols to
* rebind are added to the existing list of rebindings, and if a given symbol
* is rebound more than once, the later rebinding will take precedence.
*/
FISHHOOK_VISIBILITY
int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel);
/*
* Rebinds as above, but only in the specified image. The header should point
* to the mach-o header, the slide should be the slide offset. Others as above.
*/
FISHHOOK_VISIBILITY
int rebind_symbols_image(void *header,
intptr_t slide,
struct rebinding rebindings[],
size_t rebindings_nel);
#ifdef __cplusplus
}
#endif //__cplusplus
#endif //fishhook_h
- "react-native-snap-carousel": "^3.9.1",
修改android 无限滑动问题
Carousel.js
import React, { Component } from 'react';
import { Animated, Easing, FlatList, I18nManager, Platform, ScrollView, View, ViewPropTypes } from 'react-native';
import PropTypes from 'prop-types';
import shallowCompare from 'react-addons-shallow-compare';
import {
defaultScrollInterpolator,
stackScrollInterpolator,
tinderScrollInterpolator,
defaultAnimatedStyles,
shiftAnimatedStyles,
stackAnimatedStyles,
tinderAnimatedStyles
} from '../utils/animations';
const IS_IOS = Platform.OS === 'ios';
// Native driver for scroll events
// See: https://facebook.github.io/react-native/blog/2017/02/14/using-native-driver-for-animated.html
const AnimatedFlatList = FlatList ? Animated.createAnimatedComponent(FlatList) : null;
const AnimatedScrollView = Animated.createAnimatedComponent(ScrollView);
// React Native automatically handles RTL layouts; unfortunately, it's buggy with horizontal ScrollView
// See https://github.com/facebook/react-native/issues/11960
// NOTE: the following variable is not declared in the constructor
// otherwise it is undefined at init, which messes with custom indexes
const IS_RTL = I18nManager.isRTL;
export default class Carousel extends Component {
static propTypes = {
data: PropTypes.array.isRequired,
renderItem: PropTypes.func.isRequired,
itemWidth: PropTypes.number, // required for horizontal carousel
itemHeight: PropTypes.number, // required for vertical carousel
sliderWidth: PropTypes.number, // required for horizontal carousel
sliderHeight: PropTypes.number, // required for vertical carousel
activeAnimationType: PropTypes.string,
activeAnimationOptions: PropTypes.object,
activeSlideAlignment: PropTypes.oneOf(['center', 'end', 'start']),
activeSlideOffset: PropTypes.number,
apparitionDelay: PropTypes.number,
autoplay: PropTypes.bool,
autoplayDelay: PropTypes.number,
autoplayInterval: PropTypes.number,
callbackOffsetMargin: PropTypes.number,
containerCustomStyle: ViewPropTypes ? ViewPropTypes.style : View.propTypes.style,
contentContainerCustomStyle: ViewPropTypes ? ViewPropTypes.style : View.propTypes.style,
enableMomentum: PropTypes.bool,
enableSnap: PropTypes.bool,
firstItem: PropTypes.number,
hasParallaxImages: PropTypes.bool,
inactiveSlideOpacity: PropTypes.number,
inactiveSlideScale: PropTypes.number,
inactiveSlideShift: PropTypes.number,
layout: PropTypes.oneOf(['default', 'stack', 'tinder']),
layoutCardOffset: PropTypes.number,
lockScrollTimeoutDuration: PropTypes.number,
lockScrollWhileSnapping: PropTypes.bool,
loop: PropTypes.bool,
loopClonesPerSide: PropTypes.number,
scrollEnabled: PropTypes.bool,
scrollInterpolator: PropTypes.func,
slideInterpolatedStyle: PropTypes.func,
slideStyle: ViewPropTypes ? ViewPropTypes.style : View.propTypes.style,
shouldOptimizeUpdates: PropTypes.bool,
swipeThreshold: PropTypes.number,
useScrollView: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
vertical: PropTypes.bool,
onBeforeSnapToItem: PropTypes.func,
onSnapToItem: PropTypes.func
};
static defaultProps = {
activeAnimationType: 'timing',
activeAnimationOptions: null,
activeSlideAlignment: 'center',
activeSlideOffset: 20,
apparitionDelay: 0,
autoplay: false,
autoplayDelay: 1000,
autoplayInterval: 3000,
callbackOffsetMargin: 5,
containerCustomStyle: {},
contentContainerCustomStyle: {},
enableMomentum: false,
enableSnap: true,
firstItem: 0,
hasParallaxImages: false,
inactiveSlideOpacity: 0.7,
inactiveSlideScale: 0.9,
inactiveSlideShift: 0,
layout: 'default',
lockScrollTimeoutDuration: 1000,
lockScrollWhileSnapping: false,
loop: false,
loopClonesPerSide: 3,
scrollEnabled: true,
slideStyle: {},
shouldOptimizeUpdates: true,
swipeThreshold: 20,
useScrollView: !AnimatedFlatList,
vertical: false
}
constructor (props) {
super(props);
this.state = {
hideCarousel: true,
interpolators: []
};
// The following values are not stored in the state because 'setState()' is asynchronous
// and this results in an absolutely crappy behavior on Android while swiping (see #156)
const initialActiveItem = this._getFirstItem(props.firstItem);
this._activeItem = initialActiveItem;
this._previousActiveItem = initialActiveItem;
this._previousFirstItem = initialActiveItem;
this._previousItemsLength = initialActiveItem;
this._mounted = false;
this._positions = [];
this._currentContentOffset = 0; // store ScrollView's scroll position
this._canFireBeforeCallback = false;
this._canFireCallback = false;
this._scrollOffsetRef = null;
this._onScrollTriggered = true; // used when momentum is enabled to prevent an issue with edges items
this._lastScrollDate = 0; // used to work around a FlatList bug
this._scrollEnabled = props.scrollEnabled !== false;
this._initPositionsAndInterpolators = this._initPositionsAndInterpolators.bind(this);
this._renderItem = this._renderItem.bind(this);
this._onSnap = this._onSnap.bind(this);
this._onLayout = this._onLayout.bind(this);
this._onScroll = this._onScroll.bind(this);
this._onScrollBeginDrag = props.enableSnap ? this._onScrollBeginDrag.bind(this) : undefined;
this._onScrollEnd = props.enableSnap || props.autoplay ? this._onScrollEnd.bind(this) : undefined;
this._onScrollEndDrag = !props.enableMomentum ? this._onScrollEndDrag.bind(this) : undefined;
this._onMomentumScrollEnd = props.enableMomentum ? this._onMomentumScrollEnd.bind(this) : undefined;
this._onTouchStart = this._onTouchStart.bind(this);
this._onTouchEnd = this._onTouchEnd.bind(this);
this._onTouchRelease = this._onTouchRelease.bind(this);
this._animated = false;
this._getKeyExtractor = this._getKeyExtractor.bind(this);
this._setScrollHandler(props);
// This bool aims at fixing an iOS bug due to scrollTo that triggers onMomentumScrollEnd.
// onMomentumScrollEnd fires this._snapScroll, thus creating an infinite loop.
this._ignoreNextMomentum = false;
// Warnings
if (!ViewPropTypes) {
console.warn('react-native-snap-carousel: It is recommended to use at least version 0.44 of React Native with the plugin');
}
if (!props.vertical && (!props.sliderWidth || !props.itemWidth)) {
console.error('react-native-snap-carousel: You need to specify both `sliderWidth` and `itemWidth` for horizontal carousels');
}
if (props.vertical && (!props.sliderHeight || !props.itemHeight)) {
console.error('react-native-snap-carousel: You need to specify both `sliderHeight` and `itemHeight` for vertical carousels');
}
if (props.apparitionDelay && !IS_IOS && !props.useScrollView) {
console.warn('react-native-snap-carousel: Using `apparitionDelay` on Android is not recommended since it can lead to rendering issues');
}
if (props.customAnimationType || props.customAnimationOptions) {
console.warn('react-native-snap-carousel: Props `customAnimationType` and `customAnimationOptions` have been renamed to `activeAnimationType` and `activeAnimationOptions`');
}
if (props.onScrollViewScroll) {
console.error('react-native-snap-carousel: Prop `onScrollViewScroll` has been removed. Use `onScroll` instead');
}
}
componentDidMount () {
const { apparitionDelay, autoplay, firstItem } = this.props;
const _firstItem = this._getFirstItem(firstItem);
const apparitionCallback = () => {
this.setState({ hideCarousel: false });
if (autoplay) {
this.startAutoplay();
}
};
this._mounted = true;
this._initPositionsAndInterpolators();
// Without 'requestAnimationFrame' or a `0` timeout, images will randomly not be rendered on Android...
requestAnimationFrame(() => {
if (!this._mounted) {
return;
}
this._snapToItem(_firstItem, false, false, true, false);
this._hackActiveSlideAnimation(_firstItem, 'start', true);
if (apparitionDelay) {
this._apparitionTimeout = setTimeout(() => {
apparitionCallback();
}, apparitionDelay);
} else {
apparitionCallback();
}
});
}
shouldComponentUpdate (nextProps, nextState) {
if (this.props.shouldOptimizeUpdates === false) {
return true;
} else {
return shallowCompare(this, nextProps, nextState);
}
}
componentDidUpdate (prevProps) {
const { interpolators } = this.state;
const { firstItem, itemHeight, itemWidth, scrollEnabled, sliderHeight, sliderWidth } = this.props;
const itemsLength = this._getCustomDataLength(this.props);
if (!itemsLength) {
return;
}
const nextFirstItem = this._getFirstItem(firstItem, this.props);
let nextActiveItem = this._activeItem || this._activeItem === 0 ? this._activeItem : nextFirstItem;
const hasNewSliderWidth = sliderWidth && sliderWidth !== prevProps.sliderWidth;
const hasNewSliderHeight = sliderHeight && sliderHeight !== prevProps.sliderHeight;
const hasNewItemWidth = itemWidth && itemWidth !== prevProps.itemWidth;
const hasNewItemHeight = itemHeight && itemHeight !== prevProps.itemHeight;
const hasNewScrollEnabled = scrollEnabled !== prevProps.scrollEnabled;
// Prevent issues with dynamically removed items
if (nextActiveItem > itemsLength - 1) {
nextActiveItem = itemsLength - 1;
}
// Handle changing scrollEnabled independent of user -> carousel interaction
if (hasNewScrollEnabled) {
this._setScrollEnabled(scrollEnabled);
}
if (interpolators.length !== itemsLength || hasNewSliderWidth ||
hasNewSliderHeight || hasNewItemWidth || hasNewItemHeight) {
this._activeItem = nextActiveItem;
this._previousItemsLength = itemsLength;
this._initPositionsAndInterpolators(this.props);
// Handle scroll issue when dynamically removing items (see #133)
// This also fixes first item's active state on Android
// Because 'initialScrollIndex' apparently doesn't trigger scroll
if (this._previousItemsLength > itemsLength) {
this._hackActiveSlideAnimation(nextActiveItem, null, true);
}
if (hasNewSliderWidth || hasNewSliderHeight || hasNewItemWidth || hasNewItemHeight) {
this._snapToItem(nextActiveItem, false, false, false, false);
}
} else if (nextFirstItem !== this._previousFirstItem && nextFirstItem !== this._activeItem) {
this._activeItem = nextFirstItem;
this._previousFirstItem = nextFirstItem;
this._snapToItem(nextFirstItem, false, true, false, false);
}
if (this.props.onScroll !== prevProps.onScroll) {
this._setScrollHandler(this.props);
}
}
componentWillUnmount () {
this._mounted = false;
this.stopAutoplay();
clearTimeout(this._apparitionTimeout);
clearTimeout(this._hackSlideAnimationTimeout);
clearTimeout(this._enableAutoplayTimeout);
clearTimeout(this._autoplayTimeout);
clearTimeout(this._snapNoMomentumTimeout);
clearTimeout(this._edgeItemTimeout);
clearTimeout(this._lockScrollTimeout);
}
get realIndex () {
return this._activeItem;
}
get currentIndex () {
return this._getDataIndex(this._activeItem);
}
get currentScrollPosition () {
return this._currentContentOffset;
}
_setScrollHandler(props) {
// Native driver for scroll events
const scrollEventConfig = {
listener: this._onScroll,
useNativeDriver: true,
};
this._scrollPos = new Animated.Value(0);
const argMapping = props.vertical
? [{ nativeEvent: { contentOffset: { y: this._scrollPos } } }]
: [{ nativeEvent: { contentOffset: { x: this._scrollPos } } }];
if (props.onScroll && Array.isArray(props.onScroll._argMapping)) {
// Because of a react-native issue https://github.com/facebook/react-native/issues/13294
argMapping.pop();
const [ argMap ] = props.onScroll._argMapping;
if (argMap && argMap.nativeEvent && argMap.nativeEvent.contentOffset) {
// Shares the same animated value passed in props
this._scrollPos =
argMap.nativeEvent.contentOffset.x ||
argMap.nativeEvent.contentOffset.y ||
this._scrollPos;
}
argMapping.push(...props.onScroll._argMapping);
}
this._onScrollHandler = Animated.event(
argMapping,
scrollEventConfig
);
}
_needsScrollView () {
const { useScrollView } = this.props;
return useScrollView || !AnimatedFlatList || this._shouldUseStackLayout() || this._shouldUseTinderLayout();
}
_needsRTLAdaptations () {
const { vertical } = this.props;
return IS_RTL && !IS_IOS && !vertical;
}
_canLockScroll () {
const { scrollEnabled, enableMomentum, lockScrollWhileSnapping } = this.props;
return scrollEnabled && !enableMomentum && lockScrollWhileSnapping;
}
_enableLoop () {
const { data, enableSnap, loop } = this.props;
return enableSnap && loop && data && data.length && data.length > 1;
}
_shouldAnimateSlides (props = this.props) {
const { inactiveSlideOpacity, inactiveSlideScale, scrollInterpolator, slideInterpolatedStyle } = props;
return inactiveSlideOpacity < 1 ||
inactiveSlideScale < 1 ||
!!scrollInterpolator ||
!!slideInterpolatedStyle ||
this._shouldUseShiftLayout() ||
this._shouldUseStackLayout() ||
this._shouldUseTinderLayout();
}
_shouldUseCustomAnimation () {
const { activeAnimationOptions } = this.props;
return !!activeAnimationOptions && !this._shouldUseStackLayout() && !this._shouldUseTinderLayout();
}
_shouldUseShiftLayout () {
const { inactiveSlideShift, layout } = this.props;
return layout === 'default' && inactiveSlideShift !== 0;
}
_shouldUseStackLayout () {
return this.props.layout === 'stack';
}
_shouldUseTinderLayout () {
return this.props.layout === 'tinder';
}
_getCustomData (props = this.props) {
const { data, loopClonesPerSide } = props;
const dataLength = data && data.length;
if (!dataLength) {
return [];
}
if (!this._enableLoop()) {
return data;
}
let previousItems = [];
let nextItems = [];
if (loopClonesPerSide > dataLength) {
const dataMultiplier = Math.floor(loopClonesPerSide / dataLength);
const remainder = loopClonesPerSide % dataLength;
for (let i = 0; i < dataMultiplier; i++) {
previousItems.push(...data);
nextItems.push(...data);
}
previousItems.unshift(...data.slice(-remainder));
nextItems.push(...data.slice(0, remainder));
} else {
previousItems = data.slice(-loopClonesPerSide);
nextItems = data.slice(0, loopClonesPerSide);
}
return previousItems.concat(data, nextItems);
}
_getCustomDataLength (props = this.props) {
const { data, loopClonesPerSide } = props;
const dataLength = data && data.length;
if (!dataLength) {
return 0;
}
return this._enableLoop() ? dataLength + (2 * loopClonesPerSide) : dataLength;
}
_getCustomIndex (index, props = this.props) {
const itemsLength = this._getCustomDataLength(props);
if (!itemsLength || (!index && index !== 0)) {
return 0;
}
return this._needsRTLAdaptations() ? itemsLength - index - 1 : index;
}
_getDataIndex (index) {
const { data, loopClonesPerSide } = this.props;
const dataLength = data && data.length;
if (!this._enableLoop() || !dataLength) {
return index;
}
if (index >= dataLength + loopClonesPerSide) {
return loopClonesPerSide > dataLength ?
(index - loopClonesPerSide) % dataLength :
index - dataLength - loopClonesPerSide;
} else if (index < loopClonesPerSide) {
// TODO: is there a simpler way of determining the interpolated index?
if (loopClonesPerSide > dataLength) {
const baseDataIndexes = [];
const dataIndexes = [];
const dataMultiplier = Math.floor(loopClonesPerSide / dataLength);
const remainder = loopClonesPerSide % dataLength;
for (let i = 0; i < dataLength; i++) {
baseDataIndexes.push(i);
}
for (let j = 0; j < dataMultiplier; j++) {
dataIndexes.push(...baseDataIndexes);
}
dataIndexes.unshift(...baseDataIndexes.slice(-remainder));
return dataIndexes[index];
} else {
return index + dataLength - loopClonesPerSide;
}
} else {
return index - loopClonesPerSide;
}
}
// Used with `snapToItem()` and 'PaginationDot'
_getPositionIndex (index) {
const { loop, loopClonesPerSide } = this.props;
return loop ? index + loopClonesPerSide : index;
}
_getFirstItem (index, props = this.props) {
const { loopClonesPerSide } = props;
const itemsLength = this._getCustomDataLength(props);
if (!itemsLength || index > itemsLength - 1 || index < 0) {
return 0;
}
return this._enableLoop() ? index + loopClonesPerSide : index;
}
_getWrappedRef () {
if (this._carouselRef && (
(this._needsScrollView() && this._carouselRef.scrollTo) ||
(!this._needsScrollView() && this._carouselRef.scrollToOffset)
)) {
return this._carouselRef;
}
// https://github.com/facebook/react-native/issues/10635
// https://stackoverflow.com/a/48786374/8412141
return this._carouselRef && this._carouselRef.getNode && this._carouselRef.getNode();
}
_getScrollEnabled () {
return this._scrollEnabled;
}
_setScrollEnabled (scrollEnabled = true) {
const wrappedRef = this._getWrappedRef();
if (!wrappedRef || !wrappedRef.setNativeProps) {
return;
}
// 'setNativeProps()' is used instead of 'setState()' because the latter
// really takes a toll on Android behavior when momentum is disabled
wrappedRef.setNativeProps({ scrollEnabled });
this._scrollEnabled = scrollEnabled;
}
_getKeyExtractor (item, index) {
return this._needsScrollView() ? `scrollview-item-${index}` : `flatlist-item-${index}`;
}
_getScrollOffset (event) {
const { vertical } = this.props;
return (event && event.nativeEvent && event.nativeEvent.contentOffset &&
event.nativeEvent.contentOffset[vertical ? 'y' : 'x']) || 0;
}
_getContainerInnerMargin (opposite = false) {
const { sliderWidth, sliderHeight, itemWidth, itemHeight, vertical, activeSlideAlignment } = this.props;
if ((activeSlideAlignment === 'start' && !opposite) ||
(activeSlideAlignment === 'end' && opposite)) {
return 0;
} else if ((activeSlideAlignment === 'end' && !opposite) ||
(activeSlideAlignment === 'start' && opposite)) {
return vertical ? sliderHeight - itemHeight : sliderWidth - itemWidth;
} else {
return vertical ? (sliderHeight - itemHeight) / 2 : (sliderWidth - itemWidth) / 2;
}
}
_getViewportOffset () {
const { sliderWidth, sliderHeight, itemWidth, itemHeight, vertical, activeSlideAlignment } = this.props;
if (activeSlideAlignment === 'start') {
return vertical ? itemHeight / 2 : itemWidth / 2;
} else if (activeSlideAlignment === 'end') {
return vertical ?
sliderHeight - (itemHeight / 2) :
sliderWidth - (itemWidth / 2);
} else {
return vertical ? sliderHeight / 2 : sliderWidth / 2;
}
}
_getCenter (offset) {
return offset + this._getViewportOffset() - this._getContainerInnerMargin();
}
_getActiveItem (offset) {
const { activeSlideOffset, swipeThreshold } = this.props;
const center = this._getCenter(offset);
const centerOffset = activeSlideOffset || swipeThreshold;
for (let i = 0; i < this._positions.length; i++) {
const { start, end } = this._positions[i];
if (center + centerOffset >= start && center - centerOffset <= end) {
return i;
}
}
const lastIndex = this._positions.length - 1;
if (this._positions[lastIndex] && center - centerOffset > this._positions[lastIndex].end) {
return lastIndex;
}
return 0;
}
_initPositionsAndInterpolators (props = this.props) {
const { data, itemWidth, itemHeight, scrollInterpolator, vertical } = props;
const sizeRef = vertical ? itemHeight : itemWidth;
if (!data || !data.length) {
return;
}
let interpolators = [];
this._positions = [];
this._getCustomData(props).forEach((itemData, index) => {
const _index = this._getCustomIndex(index, props);
let animatedValue;
this._positions[index] = {
start: index * sizeRef,
end: index * sizeRef + sizeRef
};
if (!this._shouldAnimateSlides(props)) {
animatedValue = new Animated.Value(1);
} else if (this._shouldUseCustomAnimation()) {
animatedValue = new Animated.Value(_index === this._activeItem ? 1 : 0);
} else {
let interpolator;
if (scrollInterpolator) {
interpolator = scrollInterpolator(_index, props);
} else if (this._shouldUseStackLayout()) {
interpolator = stackScrollInterpolator(_index, props);
} else if (this._shouldUseTinderLayout()) {
interpolator = tinderScrollInterpolator(_index, props);
}
if (!interpolator || !interpolator.inputRange || !interpolator.outputRange) {
interpolator = defaultScrollInterpolator(_index, props);
}
animatedValue = this._scrollPos.interpolate({
...interpolator,
extrapolate: 'clamp'
});
}
interpolators.push(animatedValue);
});
this.setState({ interpolators });
}
_getSlideAnimation (index, toValue) {
const { interpolators } = this.state;
const { activeAnimationType, activeAnimationOptions } = this.props;
const animatedValue = interpolators && interpolators[index];
if (!animatedValue && animatedValue !== 0) {
return null;
}
const animationCommonOptions = {
isInteraction: false,
useNativeDriver: true,
...activeAnimationOptions,
toValue: toValue
};
return Animated.parallel([
Animated['timing'](
animatedValue,
{ ...animationCommonOptions, easing: Easing.linear }
),
Animated[activeAnimationType](
animatedValue,
{ ...animationCommonOptions }
)
]);
}
_playCustomSlideAnimation (current, next) {
const { interpolators } = this.state;
const itemsLength = this._getCustomDataLength();
const _currentIndex = this._getCustomIndex(current);
const _currentDataIndex = this._getDataIndex(_currentIndex);
const _nextIndex = this._getCustomIndex(next);
const _nextDataIndex = this._getDataIndex(_nextIndex);
let animations = [];
// Keep animations in sync when looping
if (this._enableLoop()) {
for (let i = 0; i < itemsLength; i++) {
if (this._getDataIndex(i) === _currentDataIndex && interpolators[i]) {
animations.push(this._getSlideAnimation(i, 0));
} else if (this._getDataIndex(i) === _nextDataIndex && interpolators[i]) {
animations.push(this._getSlideAnimation(i, 1));
}
}
} else {
if (interpolators[current]) {
animations.push(this._getSlideAnimation(current, 0));
}
if (interpolators[next]) {
animations.push(this._getSlideAnimation(next, 1));
}
}
Animated.parallel(animations, { stopTogether: false }).start();
}
_hackActiveSlideAnimation (index, goTo, force = false) {
const { data } = this.props;
if (!this._mounted || !this._carouselRef || !this._positions[index] || (!force && this._enableLoop())) {
return;
}
const offset = this._positions[index] && this._positions[index].start;
if (!offset && offset !== 0) {
return;
}
const itemsLength = data && data.length;
const direction = goTo || itemsLength === 1 ? 'start' : 'end';
this._scrollTo(offset + (direction === 'start' ? -1 : 1), false);
clearTimeout(this._hackSlideAnimationTimeout);
this._hackSlideAnimationTimeout = setTimeout(() => {
this._scrollTo(offset, false);
}, 50); // works randomly when set to '0'
}
_lockScroll () {
const { lockScrollTimeoutDuration } = this.props;
clearTimeout(this._lockScrollTimeout);
this._lockScrollTimeout = setTimeout(() => {
this._releaseScroll();
}, lockScrollTimeoutDuration);
this._setScrollEnabled(false);
}
_releaseScroll () {
clearTimeout(this._lockScrollTimeout);
this._setScrollEnabled(true);
}
_repositionScroll (index) {
const { data, loopClonesPerSide } = this.props;
const dataLength = data && data.length;
if (!this._enableLoop() || !dataLength ||
(index >= loopClonesPerSide && index < dataLength + loopClonesPerSide)) {
return;
}
let repositionTo = index;
if (index >= dataLength + loopClonesPerSide) {
repositionTo = index - dataLength;
} else if (index < loopClonesPerSide) {
repositionTo = index + dataLength;
}
this._snapToItem(repositionTo, false, false, false, false);
}
_scrollTo (offset, animated = true) {
const { vertical } = this.props;
const wrappedRef = this._getWrappedRef();
if (!this._mounted || !wrappedRef) {
return;
}
const specificOptions = this._needsScrollView() ? {
x: vertical ? 0 : offset,
y: vertical ? offset : 0
} : {
offset
};
const options = {
...specificOptions,
animated
};
// if (this._needsScrollView()) {
// wrappedRef.scrollTo(options);
// } else {
// wrappedRef.scrollToOffset(options);
// }
setTimeout(() => {
if (this._needsScrollView()) {
wrappedRef.scrollTo(options);
} else {
wrappedRef.scrollToOffset(options);
}
}, (!animated && this._animated) ? 200 : 0);
this._animated = animated;
}
_onScroll (event) {
const { callbackOffsetMargin, enableMomentum, onScroll } = this.props;
const scrollOffset = event ? this._getScrollOffset(event) : this._currentContentOffset;
const nextActiveItem = this._getActiveItem(scrollOffset);
const itemReached = nextActiveItem === this._itemToSnapTo;
const scrollConditions =
scrollOffset >= this._scrollOffsetRef - callbackOffsetMargin &&
scrollOffset <= this._scrollOffsetRef + callbackOffsetMargin;
this._currentContentOffset = scrollOffset;
this._onScrollTriggered = true;
this._lastScrollDate = Date.now();
if (this._activeItem !== nextActiveItem && this._shouldUseCustomAnimation()) {
this._playCustomSlideAnimation(this._activeItem, nextActiveItem);
}
if (enableMomentum) {
clearTimeout(this._snapNoMomentumTimeout);
if (this._activeItem !== nextActiveItem) {
this._activeItem = nextActiveItem;
}
if (itemReached) {
if (this._canFireBeforeCallback) {
this._onBeforeSnap(this._getDataIndex(nextActiveItem));
}
if (scrollConditions && this._canFireCallback) {
this._onSnap(this._getDataIndex(nextActiveItem));
}
}
} else if (this._activeItem !== nextActiveItem && itemReached) {
if (this._canFireBeforeCallback) {
this._onBeforeSnap(this._getDataIndex(nextActiveItem));
}
if (scrollConditions) {
this._activeItem = nextActiveItem;
if (this._canLockScroll()) {
this._releaseScroll();
}
if (this._canFireCallback) {
this._onSnap(this._getDataIndex(nextActiveItem));
}
}
}
if (nextActiveItem === this._itemToSnapTo &&
// scrollOffset === this._scrollOffsetRef) {
Math.abs(scrollOffset - this._scrollOffsetRef) <= 1.0) {
this._repositionScroll(nextActiveItem);
}
if (typeof onScroll === "function" && event) {
onScroll(event);
}
}
_onStartShouldSetResponderCapture (event) {
const { onStartShouldSetResponderCapture } = this.props;
if (onStartShouldSetResponderCapture) {
onStartShouldSetResponderCapture(event);
}
return this._getScrollEnabled();
}
_onTouchStart () {
const { onTouchStart } = this.props
// `onTouchStart` is fired even when `scrollEnabled` is set to `false`
if (this._getScrollEnabled() !== false && this._autoplaying) {
this.pauseAutoPlay();
}
if (onTouchStart) {
onTouchStart()
}
}
_onTouchEnd () {
const { onTouchEnd } = this.props
if (this._getScrollEnabled() !== false && this._autoplay && !this._autoplaying) {
// This event is buggy on Android, so a fallback is provided in _onScrollEnd()
this.startAutoplay();
}
if (onTouchEnd) {
onTouchEnd()
}
}
// Used when `enableSnap` is ENABLED
_onScrollBeginDrag (event) {
const { onScrollBeginDrag } = this.props;
if (!this._getScrollEnabled()) {
return;
}
this._scrollStartOffset = this._getScrollOffset(event);
this._scrollStartActive = this._getActiveItem(this._scrollStartOffset);
this._ignoreNextMomentum = false;
// this._canFireCallback = false;
if (onScrollBeginDrag) {
onScrollBeginDrag(event);
}
}
// Used when `enableMomentum` is DISABLED
_onScrollEndDrag (event) {
const { onScrollEndDrag } = this.props;
if (this._carouselRef) {
this._onScrollEnd && this._onScrollEnd();
}
if (onScrollEndDrag) {
onScrollEndDrag(event);
}
}
// Used when `enableMomentum` is ENABLED
_onMomentumScrollEnd (event) {
const { onMomentumScrollEnd } = this.props;
if (this._carouselRef) {
this._onScrollEnd && this._onScrollEnd();
}
if (onMomentumScrollEnd) {
onMomentumScrollEnd(event);
}
}
_onScrollEnd (event) {
const { autoplayDelay, enableSnap } = this.props;
if (this._ignoreNextMomentum) {
// iOS fix
this._ignoreNextMomentum = false;
return;
}
if (this._currentContentOffset === this._scrollEndOffset) {
return;
}
this._scrollEndOffset = this._currentContentOffset;
this._scrollEndActive = this._getActiveItem(this._scrollEndOffset);
if (enableSnap) {
this._snapScroll(this._scrollEndOffset - this._scrollStartOffset);
}
// The touchEnd event is buggy on Android, so this will serve as a fallback whenever needed
// https://github.com/facebook/react-native/issues/9439
if (this._autoplay && !this._autoplaying) {
clearTimeout(this._enableAutoplayTimeout);
this._enableAutoplayTimeout = setTimeout(() => {
this.startAutoplay();
}, autoplayDelay + 50);
}
}
// Due to a bug, this event is only fired on iOS
// https://github.com/facebook/react-native/issues/6791
// it's fine since we're only fixing an iOS bug in it, so ...
_onTouchRelease (event) {
const { enableMomentum } = this.props;
if (enableMomentum && IS_IOS) {
clearTimeout(this._snapNoMomentumTimeout);
this._snapNoMomentumTimeout = setTimeout(() => {
this._snapToItem(this._activeItem);
}, 100);
}
}
_onLayout (event) {
const { onLayout } = this.props;
// Prevent unneeded actions during the first 'onLayout' (triggered on init)
if (this._onLayoutInitDone) {
this._initPositionsAndInterpolators();
this._snapToItem(this._activeItem, false, false, false, false);
} else {
this._onLayoutInitDone = true;
}
if (onLayout) {
onLayout(event);
}
}
_snapScroll (delta) {
const { swipeThreshold } = this.props;
// When using momentum and releasing the touch with
// no velocity, scrollEndActive will be undefined (iOS)
if (!this._scrollEndActive && this._scrollEndActive !== 0 && IS_IOS) {
this._scrollEndActive = this._scrollStartActive;
}
if (this._scrollStartActive !== this._scrollEndActive) {
// Snap to the new active item
this._snapToItem(this._scrollEndActive);
} else {
// Snap depending on delta
if (delta > 0) {
if (delta > swipeThreshold) {
this._snapToItem(this._scrollStartActive + 1);
} else {
this._snapToItem(this._scrollEndActive);
}
} else if (delta < 0) {
if (delta < -swipeThreshold) {
this._snapToItem(this._scrollStartActive - 1);
} else {
this._snapToItem(this._scrollEndActive);
}
} else {
// Snap to current
this._snapToItem(this._scrollEndActive);
}
}
}
_snapToItem (index, animated = true, fireCallback = true, initial = false, lockScroll = true) {
const { enableMomentum, onSnapToItem, onBeforeSnapToItem } = this.props;
const itemsLength = this._getCustomDataLength();
const wrappedRef = this._getWrappedRef();
if (!itemsLength || !wrappedRef) {
return;
}
if (!index || index < 0) {
index = 0;
} else if (itemsLength > 0 && index >= itemsLength) {
index = itemsLength - 1;
}
if (index !== this._previousActiveItem) {
this._previousActiveItem = index;
// Placed here to allow overscrolling for edges items
if (lockScroll && this._canLockScroll()) {
this._lockScroll();
}
if (fireCallback) {
if (onBeforeSnapToItem) {
this._canFireBeforeCallback = true;
}
if (onSnapToItem) {
this._canFireCallback = true;
}
}
}
this._itemToSnapTo = index;
this._scrollOffsetRef = this._positions[index] && this._positions[index].start;
this._onScrollTriggered = false;
if (!this._scrollOffsetRef && this._scrollOffsetRef !== 0) {
return;
}
this._scrollTo(this._scrollOffsetRef, animated);
this._scrollEndOffset = this._currentContentOffset;
if (enableMomentum) {
// iOS fix, check the note in the constructor
if (!initial) {
this._ignoreNextMomentum = true;
}
// When momentum is enabled and the user is overscrolling or swiping very quickly,
// 'onScroll' is not going to be triggered for edge items. Then callback won't be
// fired and loop won't work since the scrollview is not going to be repositioned.
// As a workaround, '_onScroll()' will be called manually for these items if a given
// condition hasn't been met after a small delay.
// WARNING: this is ok only when relying on 'momentumScrollEnd', not with 'scrollEndDrag'
if (index === 0 || index === itemsLength - 1) {
clearTimeout(this._edgeItemTimeout);
this._edgeItemTimeout = setTimeout(() => {
if (!initial && index === this._activeItem && !this._onScrollTriggered) {
this._onScroll();
}
}, 250);
}
}
}
_onBeforeSnap (index) {
const { onBeforeSnapToItem } = this.props;
if (!this._carouselRef) {
return;
}
this._canFireBeforeCallback = false;
onBeforeSnapToItem && onBeforeSnapToItem(index);
}
_onSnap (index) {
const { onSnapToItem } = this.props;
if (!this._carouselRef) {
return;
}
this._canFireCallback = false;
onSnapToItem && onSnapToItem(index);
}
startAutoplay () {
const { autoplayInterval, autoplayDelay } = this.props;
this._autoplay = true;
if (this._autoplaying) {
return;
}
clearTimeout(this._autoplayTimeout);
this._autoplayTimeout = setTimeout(() => {
this._autoplaying = true;
this._autoplayInterval = setInterval(() => {
if (this._autoplaying) {
this.snapToNext();
}
}, autoplayInterval);
}, autoplayDelay);
}
pauseAutoPlay () {
this._autoplaying = false;
clearTimeout(this._autoplayTimeout);
clearTimeout(this._enableAutoplayTimeout);
clearInterval(this._autoplayInterval);
}
stopAutoplay () {
this._autoplay = false;
this.pauseAutoPlay();
}
snapToItem (index, animated = true, fireCallback = true) {
if (!index || index < 0) {
index = 0;
}
const positionIndex = this._getPositionIndex(index);
if (positionIndex === this._activeItem) {
return;
}
this._snapToItem(positionIndex, animated, fireCallback);
}
snapToNext (animated = true, fireCallback = true) {
const itemsLength = this._getCustomDataLength();
let newIndex = this._activeItem + 1;
if (newIndex > itemsLength - 1) {
if (!this._enableLoop()) {
return;
}
newIndex = 0;
}
this._snapToItem(newIndex, animated, fireCallback);
}
snapToPrev (animated = true, fireCallback = true) {
const itemsLength = this._getCustomDataLength();
let newIndex = this._activeItem - 1;
if (newIndex < 0) {
if (!this._enableLoop()) {
return;
}
newIndex = itemsLength - 1;
}
this._snapToItem(newIndex, animated, fireCallback);
}
// https://github.com/facebook/react-native/issues/1831#issuecomment-231069668
triggerRenderingHack (offset) {
// Avoid messing with user scroll
if (Date.now() - this._lastScrollDate < 500) {
return;
}
const scrollPosition = this._currentContentOffset;
if (!scrollPosition && scrollPosition !== 0) {
return;
}
const scrollOffset = offset || (scrollPosition === 0 ? 1 : -1);
this._scrollTo(scrollPosition + scrollOffset, false);
}
_getSlideInterpolatedStyle (index, animatedValue) {
const { layoutCardOffset, slideInterpolatedStyle } = this.props;
if (slideInterpolatedStyle) {
return slideInterpolatedStyle(index, animatedValue, this.props);
} else if (this._shouldUseTinderLayout()) {
return tinderAnimatedStyles(index, animatedValue, this.props, layoutCardOffset);
} else if (this._shouldUseStackLayout()) {
return stackAnimatedStyles(index, animatedValue, this.props, layoutCardOffset);
} else if (this._shouldUseShiftLayout()) {
return shiftAnimatedStyles(index, animatedValue, this.props);
} else {
return defaultAnimatedStyles(index, animatedValue, this.props);
}
}
_renderItem ({ item, index }) {
const { interpolators } = this.state;
const {
hasParallaxImages,
itemWidth,
itemHeight,
keyExtractor,
renderItem,
sliderHeight,
sliderWidth,
slideStyle,
vertical
} = this.props;
const animatedValue = interpolators && interpolators[index];
if (!animatedValue && animatedValue !== 0) {
return null;
}
const animate = this._shouldAnimateSlides();
const Component = animate ? Animated.View : View;
const animatedStyle = animate ? this._getSlideInterpolatedStyle(index, animatedValue) : {};
const parallaxProps = hasParallaxImages ? {
scrollPosition: this._scrollPos,
carouselRef: this._carouselRef,
vertical,
sliderWidth,
sliderHeight,
itemWidth,
itemHeight
} : undefined;
const mainDimension = vertical ? { height: itemHeight } : { width: itemWidth };
const specificProps = this._needsScrollView() ? {
key: keyExtractor ? keyExtractor(item, index) : this._getKeyExtractor(item, index)
} : {};
return (
<Component style={[mainDimension, slideStyle, animatedStyle]} pointerEvents={'box-none'} {...specificProps}>
{ renderItem({ item, index }, parallaxProps) }
</Component>
);
}
_getComponentOverridableProps () {
const {
enableMomentum,
itemWidth,
itemHeight,
loopClonesPerSide,
sliderWidth,
sliderHeight,
vertical
} = this.props;
const visibleItems = Math.ceil(vertical ?
sliderHeight / itemHeight :
sliderWidth / itemWidth) + 1;
const initialNumPerSide = this._enableLoop() ? loopClonesPerSide : 2;
const initialNumToRender = visibleItems + (initialNumPerSide * 2);
const maxToRenderPerBatch = 1 + (initialNumToRender * 2);
const windowSize = maxToRenderPerBatch;
const specificProps = !this._needsScrollView() ? {
initialNumToRender: initialNumToRender,
maxToRenderPerBatch: maxToRenderPerBatch,
windowSize: windowSize
// updateCellsBatchingPeriod
} : {};
return {
decelerationRate: enableMomentum ? 0.9 : 'fast',
showsHorizontalScrollIndicator: false,
showsVerticalScrollIndicator: false,
overScrollMode: 'never',
automaticallyAdjustContentInsets: false,
directionalLockEnabled: true,
pinchGestureEnabled: false,
scrollsToTop: false,
removeClippedSubviews: !this._needsScrollView(),
inverted: this._needsRTLAdaptations(),
// renderToHardwareTextureAndroid: true,
...specificProps
};
}
_getComponentStaticProps () {
const { hideCarousel } = this.state;
const {
containerCustomStyle,
contentContainerCustomStyle,
keyExtractor,
sliderWidth,
sliderHeight,
style,
vertical
} = this.props;
const containerStyle = [
containerCustomStyle || style || {},
hideCarousel ? { opacity: 0 } : {},
vertical ?
{ height: sliderHeight, flexDirection: 'column' } :
// LTR hack; see https://github.com/facebook/react-native/issues/11960
// and https://github.com/facebook/react-native/issues/13100#issuecomment-328986423
{ width: sliderWidth, flexDirection: this._needsRTLAdaptations() ? 'row-reverse' : 'row' }
];
const contentContainerStyle = [
vertical ? {
paddingTop: this._getContainerInnerMargin(),
paddingBottom: this._getContainerInnerMargin(true)
} : {
paddingLeft: this._getContainerInnerMargin(),
paddingRight: this._getContainerInnerMargin(true)
},
contentContainerCustomStyle || {}
];
const specificProps = !this._needsScrollView() ? {
// extraData: this.state,
renderItem: this._renderItem,
numColumns: 1,
keyExtractor: keyExtractor || this._getKeyExtractor
} : {};
return {
ref: c => this._carouselRef = c,
data: this._getCustomData(),
style: containerStyle,
contentContainerStyle: contentContainerStyle,
horizontal: !vertical,
scrollEventThrottle: 1,
onScroll: this._onScrollHandler,
onScrollBeginDrag: this._onScrollBeginDrag,
onScrollEndDrag: this._onScrollEndDrag,
onMomentumScrollEnd: this._onMomentumScrollEnd,
onResponderRelease: this._onTouchRelease,
onStartShouldSetResponderCapture: this._onStartShouldSetResponderCapture,
onTouchStart: this._onTouchStart,
onTouchEnd: this._onScrollEnd,
onLayout: this._onLayout,
...specificProps
};
}
render () {
const { data, renderItem, useScrollView } = this.props;
if (!data || !renderItem) {
return null;
}
const props = {
...this._getComponentOverridableProps(),
...this.props,
...this._getComponentStaticProps()
};
const ScrollViewComponent = typeof useScrollView === 'function' ? useScrollView : AnimatedScrollView
return this._needsScrollView() ? (
<ScrollViewComponent {...props}>
{
this._getCustomData().map((item, index) => {
return this._renderItem({ item, index });
})
}
</ScrollViewComponent>
) : (
<AnimatedFlatList {...props} />
);
}
}
- ios 打包
UIWebView 解决苹果上架问题
https://blog.csdn.net/sinat_30949835/article/details/107491719
9.android 二维码识别
@cubeking/react-native-qr-scanner 修改scanningImage方法
public Result scanningImage(String path) {
if (path == null || path.length() == 0) {
return null;
}
Hashtable<DecodeHintType, String> hints = new Hashtable<>();
hints.put(DecodeHintType.CHARACTER_SET, "UTF8"); //设置二维码内容的编码
String replaceCode = path.replace("data:image/png;base64,", "");
byte[] bitmapByte = Base64.decode(replaceCode, Base64.DEFAULT);
Bitmap scanBitmap = BitmapFactory.decodeByteArray(bitmapByte, 0, bitmapByte.length);
// BitmapFactory.Options options = new BitmapFactory.Options();
// options.inJustDecodeBounds = true; // 先获取原大小
// Bitmap scanBitmap = BitmapFactory.decodeFile(path, options);
// options.inJustDecodeBounds = false; // 获取新的大小
// int sampleSize = (int) (options.outHeight / (float) 200);
// if (sampleSize <= 0)
// sampleSize = 1;
// options.inSampleSize = sampleSize;
// scanBitmap = BitmapFactory.decodeFile(path, options);
int width=scanBitmap.getWidth();
int height=scanBitmap.getHeight();
int[] pixels=new int[width*height];
scanBitmap.getPixels(pixels,0,width,0,0,width,height);//获取图片像素点
RGBLuminanceSource source = new RGBLuminanceSource(scanBitmap.getWidth(),scanBitmap.getHeight(),pixels);
BinaryBitmap bitmap1 = new BinaryBitmap(new HybridBinarizer(source));
QRCodeReader reader = new QRCodeReader();
try {
return reader.decode(bitmap1, hints);
} catch (NotFoundException e) {
e.printStackTrace();
} catch (ChecksumException e) {
e.printStackTrace();
} catch (FormatException e) {
e.printStackTrace();
}
return null;
}